# XSD konfigurieren mit eigenen Typen



## lam_tr (12. Mrz 2020)

Hallo zusammen,

ich habe folgendes Schema

```
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc" jaxb:version="2.0">

    <xs:annotation>
        <xs:appinfo>
            <jaxb:globalBindings>
                <xjc:serializable uid="1" />
            </jaxb:globalBindings>
        </xs:appinfo>
    </xs:annotation>

  <xs:element  name="CONTENT" type="Content"/>
 
   <xs:complexType name="Content">
    <xs:sequence>
      <xs:element minOccurs="0" name="INFO" type="Info"/>
      <xs:element minOccurs="0" name="DESCR" type="Description"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Info"/>
  <xs:complexType name="Description"/>
</xs:schema>
```

wie kann ich das Schema mit xmlns so definieren, dass in meiner XML Datei diesen Namensraum habe? Es scheint nicht gültig zu sein weil ich den Default NS überschreiben möchte.


```
<?xml version="1.0" encoding="UTF-8"?>
<CONTENT xmlns="http://example.com/content">
  <INFO/>
  <DESCR/>
</CONTENT>
```

Hier noch die Fehlermeldung, wenn ich den Namensraum direkt in das XSD hinzufüge

```
src-resolve.4.2: Error resolving component 'Content'. It was detected that 'Content' is in
 namespace 'http://example.com/content', but components from this namespace are not
 referenceable from schema document...
```


Hat da jemand eine Idee für mich? Ich weiß zwar was ein NS ist, aber das mit der Definition in XSD hänge ich gerade.

Viele Grüße
lam


----------



## kneitzel (12. Mrz 2020)

Im xsd solltest Du targetNamespace definieren. Wenn es http://example.com/content sein soll, dann solltest Du das so schreiben:

```
<xs:schema ..... targetNamespace="http://example.com/content" ....>
```

Und wie nutzt Du es? Gibst Du das xsd bereits mit an, so dass es bekannt ist? Wenn es automatisch geladen werden soll, dann könntest Du im xml noch angeben: xsi:schemaLocation="<URL der XSD Datei>" also  z.b. sowas wie xsi:schemaLocation="https://my.cool.comain/myXsdFile.xsd"


----------



## lam_tr (12. Mrz 2020)

JustNobody hat gesagt.:


> Im xsd solltest Du targetNamespace definieren. Wenn es http://example.com/content sein soll, dann solltest Du das so schreiben:
> 
> ```
> <xs:schema ..... targetNamespace="http://example.com/content" ....>
> ...



Vielen Dank für die schnelle Antwort.

Wenn ich der XML die XSD nicht mitbegebe, dann funktioniert das mit dem TargetNamespace nicht.

Ich habe stattdessen im xs:schema xmlns:ct="http://www.example.com/content" erweitert.

Bin mir nicht sicher ob das der richtige Weg ist, auf jeden Fall validiert die XML jetzt.

Was meinst du dazu?


----------



## kneitzel (12. Mrz 2020)

Also in der xsd gibst Du im xs tag an:
- xmlns[:Kürzel]="..." Namespaces, die Du selbst nutzen willst. (Hast Du ja mehrere, xs, xjc, ...
- targetNamespace="..." Welchen Namespace beschreibst Du denn in dem xsd File?

Daher würde ich das xsd so erweitern:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc" jaxb:version="2.0"
*    targetNamespace="http://example.com/content"*>

Das mal ohne code-Tags damit das zusätzliche sichtbar ist, das ich einfügen würde.

Denn so erkennt das System nun, dass das xsd eben http://example.com/content definiert. (Da solltest Du aber nicht example.com verwenden, aber das war evtl. ja nur ein Beispiel...)

Das XML sollte dann so ok sein. Also einfach mit dem ersten Element so anfangen und daden default Namespace setzen. Du kannst natürlich auch ein benannten Namespace nehmen indem du da xmlns:ct="..." statt xmlns="..." nutzt, aber dann musst Du natürlich den Elementen den Namespace ct: voran stellen. Aber das xml sollte so ok sein, wie du es in #1 angegeben hast.

Wenn Du dem Parser im Code nicht das xsd schon mitgibst, dann müsste er wissen, wo er das xsd File findet. Das ist, was ich noch kurz mit schemaLocation angesprochen habe. Das wäre dann etwas wie:


```
<?xml version="1.0"?>
<CONTENT xmlns="http://example.com/content"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://valid url/to/xsd_file.xsd">
```


----------



## lam_tr (12. Mrz 2020)

Vielen Dank für die detaillierte Erklärung. Die XSD wird bei XML nicht mitgegeben. 

Die Validierung geschieht in dieser Form programmatisch.


```
public static void main(String[] args) {
        XMLValidator XMLValidator = new XMLValidator();
        boolean valid = XMLValidator.validate(XML_FILE, SCHEMA_FILE);

        System.out.printf("%s validation = %b.", XML_FILE, valid);
    }

    private boolean validate(String xmlFile, String schemaFile) {
        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        try {
            Schema schema = schemaFactory.newSchema(new File(SCHEMA_FILE));

            Validator validator = schema.newValidator();
            validator.validate(new StreamSource(new File(XML_FILE)));
            return true;
        } catch (SAXException | IOException e) {
            e.printStackTrace();
            return false;
        }
    }
```

Grüße
lam


----------



## kneitzel (12. Mrz 2020)

Ja, das meinte ich. Du lädst das Schema bereits im Programm. Damit brauchst Du das xsi:schemaLocation und den xsi Namespace nicht im XML.

Und dank Deines Codes habe ich das jetzt auch noch einmal schnell getestet. Was ich natürlich übersehen habe:
Du definierst keinen default Namespace. Du definierst einen Typ "Context" und der hat damit kein Namespace. Setz noch den default namespace in der xsd Datei:


```
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc" jaxb:version="2.0"
    targetNamespace="http://example.com/content" xmlns="http://example.com/content">
```

Damit funktioniert es dann auch mit Deinem Code.

Zur Vollständigkeit einfach einmal, was ich erfolgreich getestet habe:

test.xml

```
<?xml version="1.0" encoding="UTF-8"?>
<CONTENT xmlns="http://example.com/content">
  <INFO/>
  <DESCR/>
</CONTENT>
```

test.xsd

```
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc" jaxb:version="2.0"
    targetNamespace="http://example.com/content" xmlns="http://example.com/content">

    <xs:annotation>
        <xs:appinfo>
            <jaxb:globalBindings>
                <xjc:serializable uid="1" />
            </jaxb:globalBindings>
        </xs:appinfo>
    </xs:annotation>

  <xs:element  name="CONTENT" type="Content"/>
 
   <xs:complexType name="Content">
    <xs:sequence>
      <xs:element minOccurs="0" name="INFO" type="Info"/>
      <xs:element minOccurs="0" name="DESCR" type="Description"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Info"/>
  <xs:complexType name="Description"/>
 
</xs:schema>
```

XMLValidator.java

```
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.File;
import java.io.IOException;

public class XMLValidator {
    public static String XML_FILE = "./test.xml";
    public static String SCHEMA_FILE = "./test.xsd";

    public static void main(String[] args) {
        XMLValidator XMLValidator = new XMLValidator();
        boolean valid = XMLValidator.validate(XML_FILE, SCHEMA_FILE);

        System.out.printf("%s validation = %b.", XML_FILE, valid);
    }

    private boolean validate(String xmlFile, String schemaFile) {
        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        try {
            Schema schema = schemaFactory.newSchema(new File(SCHEMA_FILE));

            Validator validator = schema.newValidator();
            validator.validate(new StreamSource(new File(XML_FILE)));
            return true;
        } catch (SAXException | IOException e) {
            e.printStackTrace();
            return false;
        }
    }
}
```


----------



## lam_tr (12. Mrz 2020)

Und nochmal Danke fürs ausführliches testen. Somit sind wir schon mal ein Schritt weiter.


----------

