2017-07-12 2 views
1

J'ai essayé de valider un fichier XML en utilisant une hiérarchie de fichiers XSD, dont certains contiennent des fichiers dtd. J'ai réussi à le faire avec succès sur la base du schéma référencé via schemaLocation dans le fichier XML en définissant les indicateurs de validation ProcessInlineSchema et ProcessSchemaLocation.Validez un XML en utilisant le schéma XSD qui contient des déclarations DTD en C#

Cependant, pour mon scénario, j'ai besoin de livrer les fichiers XSD avec l'application que je construis, donc le schemaLocation devrait être ignoré (car il pointera vers quelque part sur le web). Les fichiers XML sont standard.

J'ai créé un exemple simple pour tester mon problème - je les fichiers suivants:

main.xsd

<?xml version="1.0" encoding="UTF-8"?> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ro:sopa:main" xmlns:main="ro:sopa:main" xmlns:inc="ro:sopa:inc" > 
    <xs:import namespace="ro:sopa:inc" schemaLocation="included.xsd"/> 
    <xs:element name="test" type="main:testType"/> 
    <xs:complexType name="testType"> 
     <xs:sequence> 
      <xs:element name="test1" type="inc:testInc" minOccurs="0" maxOccurs="unbounded"/> 
     </xs:sequence> 
    </xs:complexType> 
</xs:schema> 

included.xsd

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE xs:schema [ 
    <!ENTITY % inc.dtd SYSTEM "inc.dtd"> 
    %inc.dtd; 
]> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ro:sopa:inc"> 
    <xs:simpleType name="testInc"> 
     <xs:restriction base="xs:string"> 
      <xs:pattern value="&test;"/> 
     </xs:restriction> 
    </xs:simpleType> 
</xs:schema> 

inc.dtd

<!ENTITY digit "[0-9]{1}"> 
<!ENTITY alnum "[A-Z]{1}"> 
<!ENTITY test "&alnum;-&digit;"> 

fichier XML Exemple:

<main:test xsi:schemaLocation="ro:sopa:main D:\schemas\main.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:main="ro:sopa:main"> 
<test1>A-4</test1> 
</main:test> 

Si je valide par rapport au schéma indiqué dans le fichier XML directement, il fonctionne correctement:

List<string> report = new List<string>(); 
XmlReaderSettings settings = new XmlReaderSettings(); 
settings.ValidationType = ValidationType.Schema; 
settings.DtdProcessing = DtdProcessing.Parse; 
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings; 
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema; 
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation; 
settings.ValidationEventHandler += new ValidationEventHandler(delegate(object snd, ValidationEventArgs e2) 
{ 
    report.Add(e2.Message); 
}); 

XmlReader reader = XmlReader.Create(fileName, settings); 

while (reader.Read()); 

reader.Close(); 

Cependant, si je tente de mettre un XmlSchemaSet manuellement, il ne fonctionnera pas .

public static string schemaUrl = @"D:\schema\main.xsd"; 
public static string fileName = @"D:\somewhere\testProd1.xml"; 

public static void Main(string[] args) 
{ 
    List<string> report = new List<string>(); 
    XmlReaderSettings settings = new XmlReaderSettings(); 
    settings.ValidationType = ValidationType.Schema; 
    settings.DtdProcessing = DtdProcessing.Parse; 
    settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings; 
    settings.Schemas = ProvideSchemaSet(report); 
    settings.ValidationEventHandler += new ValidationEventHandler(delegate(object snd, ValidationEventArgs e2) 
    { 
     report.Add(e2.Message); 
    }); 

    XmlReader reader = XmlReader.Create(fileName, settings); 
    while (reader.Read()) ; 
    reader.Close(); 
} 

public static XmlSchemaSet ProvideSchemaSet(List<string> schemaLoadErrors) 
{ 
    XmlSchemaSet schemas = new XmlSchemaSet(); 

    XmlReaderSettings settings = new XmlReaderSettings(); 
    settings.DtdProcessing = DtdProcessing.Parse; 
    XmlReader schemaReader = XmlReader.Create(schemaUrl, settings); 

    XmlSchema schema = XmlSchema.Read(schemaReader, delegate(object sender, ValidationEventArgs e) 
    { 
     schemaLoadErrors.Add(e.Message); 
    }); 

    schemas.Add(schema); 
    schemaReader.Close(); 

    schemas.Compile(); 
    return schemas; 
} 

Cela se bloquera sur schemas.Compile() en disant que l'objet test1 n'existe pas. Cela ne se produit que si j'utilise le dtd - si je retire la DTD du schéma, cela fonctionne correctement. Tout ce que j'ai cherché sur internet était spécifiquement à propos de la validation XSD ou de la validation de la DTD - mais je n'ai trouvé aucune solution pour cela. Aucune suggestion?

Remarque: Les schémas et les DTD avec lesquels je dois travailler sont standardisés, donc je ne peux pas les modifier de quelque façon que ce soit.

Répondre

0

Vous pouvez re-charger le XSD, le traitement de la partie DTD puis de le retirer

 XmlReaderSettings xrs = new XmlReaderSettings(); 
     xrs.DtdProcessing = DtdProcessing.Parse; 
     xrs.IgnoreProcessingInstructions = false; 
     xrs.XmlResolver = new XmlUrlResolver(); 
     XmlReader reader = XmlReader.Create(@"c:\temp\xsd\included.xsd", xrs); 

     XmlDocument xmldoc = new XmlDocument(); 
     xmldoc.Load(reader); 
     Debug.WriteLine(xmldoc.OuterXml); 

Cela vous donne un document XML qui ressemble à ceci

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE xs:schema[ 
    <!ENTITY % inc.dtd SYSTEM "inc.dtd">%inc.dtd; 
]> 
<!-- Created with Liquid Studio 2018 BETA - Developer Bundle (Educational) 16.0.0.7863 (https://www.liquid-technologies.com) --> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ro:sopa:inc"> 
    <xs:simpleType name="testInc"> 
     <xs:restriction base="xs:string"> 
      <xs:pattern value="[A-Z]{1}-[0-9]{1}" /> 
     </xs:restriction> 
    </xs:simpleType> 
</xs:schema> 

Vous pouvez ensuite retirer le Doctype (qui gâche probablement la compilation XSD)

<?xml version="1.0" encoding="UTF-8"?> 
<!-- Created with Liquid Studio 2018 BETA - Developer Bundle (Educational) 16.0.0.7863 (https://www.liquid-technologies.com) --> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ro:sopa:inc"> 
    <xs:simpleType name="testInc"> 
     <xs:restriction base="xs:string"> 
      <xs:pattern value="[A-Z]{1}-[0-9]{1}" /> 
     </xs:restriction> 
    </xs:simpleType> 
</xs:schema> 

Bien que son droit d'intégrer une DTD dans un XSD Je pense que une mauvaise idée, il jette vraiment beaucoup de validateurs et des outils.