#xml #f# #xml-namespaces #type-providers
#xml #f# #xml-пространства имен #поставщики типов
Вопрос:
Я пытался проанализировать сообщение XML NLog с помощью XMLProvider. В моем проекте я определил поставщика следующим образом:
XmlProvider<"""
<log4j:event
logger="MyTest" level="INFO" timestamp="1597329370954" thread="1">
<log4j:message>
Running task
</log4j:message>
<log4j:locationInfo class="My.Task" method="Void main(System.String[])" />
<nlog:eventSequenceNumber>
11
</nlog:eventSequenceNumber>
<nlog:locationInfo assembly="My.Task, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<nlog:properties />
<log4j:properties>
<data name="log4japp" value="My.Task(64400)" />
<data name="log4jmachinename" value="BNT" />
</log4j:properties>
</log4j:event>""">
Но это не компилируется, поскольку я получаю исключения из-за отсутствия определений пространства имен.
Итак, я добавил xmlns к корневому элементу, сделав его:
XmlProvider<"""
<log4j:event
xmlns:log4j="http://jakarta.apache.org/log4j/"
xmlns:nlog="http://www.nlog-project.org/schemas/NLog.xsd"
logger="MyTest" level="INFO" timestamp="1597329370954" thread="1">
<log4j:message>
...
...
</log4j:event>""">
И это помогает моему проекту компилироваться, но во время выполнения при попытке проанализировать XML возникает исключение:
'log4j' is an undeclared prefix. Line 1, position 2.
Я справился с проблемой, предварительно обработав xml и удалив все пространства имен xml из всех тегов. Хотя это работает, мне интересно, есть ли решение получше.
Комментарии:
1. У меня это работает.
Ответ №1:
У меня это работает нормально, но вам нужно включить объявления пространства имен XML как в образец XML, так и в фактические данные. Например, отлично работает следующее:
// Simplified declaration with namespaces included
type X = XmlProvider<"""
<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/"
xmlns:nlog="http://www.nlog-project.org/schemas/NLog.xsd">
<log4j:message>Running task</log4j:message>
<nlog:eventSequenceNumber>11</nlog:eventSequenceNumber>
</log4j:event>""">
// Load a sample data file with namespaces included
let x = X.Parse("""
<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/"
xmlns:nlog="http://www.nlog-project.org/schemas/NLog.xsd">
<log4j:message>Running task</log4j:message>
<nlog:eventSequenceNumber>11</nlog:eventSequenceNumber>
</log4j:event>""")
// Returns the data from the XML just fine!
x.Message
x.EventSequenceNumber
Если вы опустите объявления пространства имен XML из данных, это приведет к сбою:
let y = X.Parse("""
<log4j:event>
<log4j:message>Running task</log4j:message>
<nlog:eventSequenceNumber>11</nlog:eventSequenceNumber>
</log4j:event>""")
Я не думаю, что есть способ указать поставщику типов XML неявно включать объявления пространств имен — я вижу, насколько это было бы полезной функцией, поэтому не стесняйтесь вносить предложения в проект GitHub!
Комментарии:
1. Включение и выключение этого всегда было спорадической проблемой с тех пор, как …. по крайней мере, 15-20 лет — начиная с XmlDocument в эпоху VB6 и заканчивая различными технологиями xml (в .NET и т.д.). Это должно быть легко, но те кэши схемы и еще много чего, которые часто приходилось настраивать в прошлом, делали это утомительным. И все это время я задавался вопросом, возможно ли это без потери корректности, если реализация xml просто говорит: «есть префикс пространства имен — значит, есть пространство имен — но меня не волнует, что именно определяет это пространство имен». Учитывая, что проверка документа обычно была дополнительным шагом в любом случае.
2. @Tomas, спасибо — это именно тот случай, поскольку в моих фрагментах XML, которые я пытаюсь проанализировать, действительно отсутствуют определения пространств имен. Спасибо, что подтвердили, что это нелегко обойти.