Я работаю с C# и .NET 8.0.6.
У меня есть XSD, который объявляет «корневой» элемент с содержимым xs:token
. Когда я проверяю документ с элементом экземпляра с дополненным содержимым, заполнение сохраняется? Я ожидаю, что отступы (начальные и конечные пробелы) будут удалены.
XSD — это:
<?xml version='1.0'?>
<xs:schema
targetNamespace = "http://example.org/scratch"
xmlns = "http://example.org/scratch"
xmlns:xs = "http://www.w3.org/2001/XMLSchema">
<xs:element name = "root" type = "xs:token"/>
</xs:schema>
Экземпляр:
<?xml version='1.0'?>
<pre:root xmlns:pre = "http://example.org/scratch"> abc </pre:root>
Мой код, который делает следующее:
XmlSchema
.SchemaSet
, который затем компилируется.XmlReader
(XsdValidatingReader
), используя: var xmlReaderSettings = new XmlReaderSettings
{
CheckCharacters = true,
DtdProcessing = DtdProcessing.Prohibit,
Schemas = xmlSchemaSet,
ValidationType = ValidationType.Schema,
};
XmlDocument.Load(xmlReader)
.Объект документа дает:
<?xml version = "1.0"?>
<pre:root xmlns:pre = "http://example.org/scratch"> abc </pre:root>
В частности, XmlDocument.DocumentElement имеет:
Я не уверен, что в .NET DOM (т. е. System.Xml.XmlDocument/XmlNode/XmlElement) вы найдете значения, типизированные схемой. Используйте XPathNavigator/XPathDocument Learn.microsoft.com/en-us/dotnet/api/… . См. также Learn.microsoft.com/en-us/dotnet/standard/data/xml/…
XmlReaderSettings.IgnoreWhitespace
было бы хорошим началом, но это значительные пробелы, потому что текст — это не только пробелы.
@YitzhakKhabinsky — Смотри второй абзац. Я не понимаю, почему начальные и конечные пробелы не были удалены из содержимого элемента, набранного как xs:token.
@Charlieface — XmlReaderSettings.IgnoreWhitespace
контролирует игнорирование незначительных пробелов. Однако пробелы в содержимом элемента имеют большое значение.
@MartinHonnen — я предполагаю, что да, поскольку, как видно в конце вопроса, SchemaInfo.SchemaType.TypeCode
: «Токен» соответствует XmlDocument.DocumentElement
. Кроме того, я только изучаю XML, поэтому пока не могу экспериментировать с XPath.
Если вы хотите, чтобы кто-то полностью исследовал логику вашего кода, вам следует опубликовать минимально воспроизводимый пример.
Вы столкнулись со своеобразными нюансами проверки XSD.
Сначала он применяет тип данных xs:token
к значению элемента, сворачивает пробелы и сразу после этого запускает проверку.
Если вам нужно сделать присутствие пробелов недействительным, попробуйте следующий XSD.
XSD
<?xml version = "1.0"?>
<xs:schema targetNamespace = "http://example.org/scratch"
xmlns = "http://example.org/scratch"
xmlns:xs = "http://www.w3.org/2001/XMLSchema">
<xs:element name = "root">
<xs:simpleType>
<xs:restriction base = "xs:string">
<xs:pattern value = "[^\s]+"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
Кажется, вы подразумеваете, что замена пробелов выполняется для проверки, но результаты не сохраняются в DOM после проверки? Однако .NET (например) дополняет проверенные экземпляры значениями по умолчанию для отсутствующих элементов. Кроме того, в приведенной вами выше ссылке (oreilly) указано, что пространством значений элемента xs:token
является строка «после замены пробелов». (См. пример.) Итак, я ожидаю замены пробелов, но подозреваю, что делаю что-то не так.
Вам нужно говорить с точки зрения результатов проверки: действительных или недействительных.
Проверка @voidp не изменяет XML, а просто проверяет, все ли в порядке. В спецификации w3.org/TR/xmlschema11-2/#token говорится, что ограничения на xs:token
(например, минимальная/максимальная длина и т. д.) применяются только после свертывания, но это не имеет ничего общего с фактическим изменением XML, это все о проверке. Если XML проверен, соответствующий десериализатор XSD затем проанализирует обрезанное значение. См., например, dotnetfiddle.net/Tt1VDR, где вы можете убедиться, что строка обрезается. Скажем так: сам XML не меняется, меняется то, что вы из него анализируете.
@Charlieface Согласен. Меня сбило с толку увеличение информационного набора. Когда я увидел, что добавляются значения по умолчанию, я ошибочно ожидал, что содержимое будет преобразовано в соответствии с типом схемы.
Заполнение не удаляется, поскольку проверка XML-схемы не изменяет содержимое экземплярного документа.
Я ошибочно предположил, что любая нормализация пробелов, примененная к xs:token
, сохраняется. Однако в спецификации XSD такие модификации не предусмотрены. Любая нормализация является внутренней для процесса проверки.
Хотя содержимое экземпляра не изменяется во время проверки, его можно дополнить. Добавление значений по умолчанию — один из примеров. Добавление информации в информационный набор после проверки схемы (PSVI) — еще один вариант.
В .NET и C# к информации PSVI узла XML можно получить доступ через XmlNode.SchemaInfo
и использовать ее для выполнения преобразования после проверки. Например, если SchemaInfo.SchemaType.TypeCode
из XmlTypeCode.Token
, приложение может нормализовать пробелы в контенте.
Я все еще думаю, что Learn.microsoft.com/en-us/dotnet/api/… должен дать вам abc
, а не `abc` , но кажется, что он действительно просто возвращает ненормализованную строку. Я скорее считаю ошибкой в этом API то, что значение xs:token
не возвращается нормализованным.
@MartinHonnen Рассмотрите возможность публикации этого на github.com/dotnet/runtime/discussions.
Я попытал счастья, чтобы поднять это как потенциальную проблему github.com/dotnet/runtime/issues/104507
Используя SaxonCS (требуется коммерческая лицензия), вы можете использовать построитель документов с поддержкой схемы для анализа входных XML-данных в документ XDM, а затем получить типизированное значение:
using Saxon.Api;
using Path = System.IO.Path;
using static Saxon.Api.Steps;
var processor = new Processor();
processor.SchemaManager.Compile(new Uri(Path.Combine(Environment.CurrentDirectory, "schema1.xsd")));
var schemaValidator = processor.SchemaManager.NewSchemaValidator();
var docBuilder = processor.NewDocumentBuilder();
docBuilder.SchemaValidator = schemaValidator;
var xdmNode = docBuilder.Build(new Uri(Path.Combine(Environment.CurrentDirectory, "sample1.xml")));
foreach (var item in xdmNode.OutermostElement.Select(Child("item")))
{
foreach (var child in item.Children())
{
Console.WriteLine($"Child {child.NodeName}: typed value: |{child.TypedValue}|");
}
}
Пример XML:
<?xml version = "1.0" encoding = "utf-8" ?>
<root>
<item>
<string> abc </string>
<token> abc </token>
<date> 2024-07-01 </date>
<tokens> foo bar baz </tokens>
</item>
<item>
<string> abc </string>
<token> abc </token>
<date> 2024-07-01 </date>
<tokens> foo bar baz </tokens>
</item>
</root>
Пример схемы:
<xs:schema xmlns:xs = "http://www.w3.org/2001/XMLSchema">
<xs:element name = "root">
<xs:complexType>
<xs:sequence maxOccurs = "unbounded">
<xs:element name = "item">
<xs:complexType>
<xs:sequence>
<xs:element name = "string" type = "xs:string"/>
<xs:element name = "token" type = "xs:token"/>
<xs:element name = "date" type = "xs:date"/>
<xs:element name = "tokens" type = "xs:NMTOKENS"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Пример вывода программы:
Child string: typed value: | abc |
Child token: typed value: |abc|
Child date: typed value: |2024-07-01|
Child tokens: typed value: |"foo"
"bar"
"baz"|
Child string: typed value: | abc |
Child token: typed value: |abc|
Child date: typed value: |2024-07-01|
Child tokens: typed value: |"foo"
"bar"
"baz"|
В чем вопрос? Посмотрите здесь: oreilly.com/library/view/xml-schema/0596002521/re95.html