使用 F# XMLProvider 解析带有命名空间的 XML

Parsing an XML with namespaces using F# XMLProvider

我一直在尝试使用 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!