使用F#XMLProvider解析具有名称空间的XML

问题描述

我一直在尝试使用XMLProvider解析XML NLog消息。 在我的项目中,我通过以下方式定义了提供程序:

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名称空间来解决了这个问题。在这种情况下,我想知道是否有更好的解决方案。

解决方法

这对我来说很好用,但是您需要在示例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项目上提出建议!