excel 如何忽略XML命名空间

eulz3vhy  于 2023-03-13  发布在  其他
关注(0)|答案(2)|浏览(159)

我有一个XML文件,该XML文件声明了名称空间

<CrystalReport  xmlns="urn:crystal-reports:schemas:report-detail"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:crystal-reports:schemas:report-detail http://www.businessobjects.com/products/xml/CR2008Schema.xsd">

这导致我在Excel中的VBA代码出现问题。当我删除上面这行的命名空间时,它工作正常。

我的问题是:如何忽略此命名空间,而不必打开xml文件并手动删除?

我使用的代码:

Public xmlDOM As MSXML2.DOMDocument60

Public Sub setXML(xmlFileName As String)

    'Set xmlDOM = CreateObject("MSXML2.DOMDocument")
    Set xmlDOM = New MSXML2.DOMDocument60
    xmlDOM.async = False
    xmlDOM.Load xmlFileName

End Sub

Public Function getNode(p_strNode As Variant) As Variant

    Dim objNodes As IXMLDOMNodeList
    Dim objNode As IXMLDOMNode
    Dim storage As Variant
    Dim X As Integer

    Set objNodes = xmlDOM.SelectNodes(p_strNode)

    Set getNode = objNodes

End Function

Public Sub SB_StartLoadClarityReport()

    Dim d_path As String
    Dim d_node As Variant
    Dim d_arrayFields As Variant

    d_path = F_GetPathXML()

    '@Temp
    d_path = Cells(1, 1).Value

    'Open XML File
    setXML (d_path)

    'Get the project fields
    Set d_node = getNode("CrystalReport/Details/Section")
    d_arrayFields = F_GetProjectFields(d_node)

End Sub

Private Function F_GetProjectFields(p_strNode As Variant)

    'Get the project fields
    'Ex: <Field Name="PROJECTNAME1" - Get PROJECTNAME1

    Dim d_arrayFields As Variant
    Dim p_item As IXMLDOMElement
    Dim d_count As Integer

    d_count = 1

    For Each p_item In p_strNode.Item(0).ChildNodes

        If d_count = 1 Then
            ReDim d_arrayFields(1 To d_count)
        Else
            ReDim Preserve d_arrayFields(1 To d_count)
        End If

        d_arrayFields(d_count) = p_item.Attributes.Item(0).Text
        d_count = d_count + 1

    Next p_item

    F_GetProjectFields = d_arrayFields

End Function
brtdzjyr

brtdzjyr1#

这对我很有效(经过一番挠头)

Sub Tester()

    Const XML As String = "<?xml version='1.0'?>" & _
    "<CrystalReport  xmlns='urn:crystal-reports:schemas:report-detail' " & _
    " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' " & _
    " xsi:schemaLocation='urn:crystal-reports:schemas:report-detail " & _
    " http://www.businessobjects.com/products/xml/CR2008Schema.xsd'>" & _
    "   <Test>Testing</Test>" & _
    "</CrystalReport>"

    Dim xmlDom As New MSXML2.DOMDocument60
    Dim nodeList As MSXML2.IXMLDOMNodeList
    Dim iNode As MSXML2.IXMLDOMNode

    With xmlDom
        .async = False
        .validateOnParse = True
        .LoadXML XML
        .setProperty "SelectionLanguage", "XPath"

        'set the default namespace and give it a prefix (e.g.) "xx"
        .setProperty "SelectionNamespaces", _
                     "xmlns:xx='urn:crystal-reports:schemas:report-detail'"

        'use the same default prefix in your XPath
        Set nodeList = .SelectNodes("//xx:Test")

    End With

    Debug.Print nodeList.Length
    For Each iNode In nodeList
        Debug.Print iNode.XML
    Next iNode

End Sub
hc8w905p

hc8w905p2#

我花了几个小时试图找到一个适当的解决方案,忽略任何名称空间,而不必在.setProperty "SelectionNamespaces"中设置它们,因为我不想更改我的.SelectNodes("//Test")代码以匹配每个可能的名称空间!
对我有效的解决方案需要使用.transformNodeToObject方法:

Public Sub fixNS(ByRef doc As DOMDocument60)
  Dim fixNS0 As New DOMDocument60
  fixNS0.LoadXML ("<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>" & _
    "<xsl:output method='xml' indent='yes' encoding='UTF-8' omit-xml-declaration='yes' />" & _
    "<xsl:template match='comment()'> <xsl:copy/> </xsl:template>" & _
    "<xsl:template match='*'>" & _
        "<xsl:text>&#xA;</xsl:text>" & _
        "<xsl:element name='{local-name(.)}'>" & _
            "<xsl:apply-templates select='@* | node()'/>" & _
        "</xsl:element>" & _
        "<xsl:text>&#xA;</xsl:text>" & _
    "</xsl:template> <xsl:template match='@*'>" & _
        "<xsl:attribute name='{local-name(.)}'><xsl:value-of select='.'/></xsl:attribute>" & _
    "</xsl:template> </xsl:stylesheet>")
  doc.transformNodeToObject fixNS0, doc
End Sub

提供的xsl:stylesheet删除了所有的命名空间,同时保留了属性和注解,但是你可以修改它来删除它们。现在我使用我的初始代码.SelectNodes("//Test"),而不用担心我加载的任何命名空间!

EDIT经过一番研究,我设法修改xsl:stylesheet以保持缩进,因为原始代码只是一个接一个地堆叠元素,所以在元素标记前后添加2个换行符(如<xsl:text>&#xA;</xsl:text>)解决了这个问题。
说明

  • 要使用该代码,需要引用Microsoft XML, v6.0
  • 您可以将整个 < xsl > 代码保存到一个外部文件.xsl中,并使用 * .load "file.xsl" * 方法代替,但我更喜欢这种方式,因为它尽可能独立!
  • 得到的xml缩进现在与原来的一样,但如果您不喜欢<tags></tags>的结尾问题,则需要使用以下 PrettyPrintXML 函数来获取<tags/>
Public Function PrettyPrintXML(XML As String) As String
   Dim Reader As New SAXXMLReader60, Writer As New MXXMLWriter60
   Writer.indent = True: Writer.standalone = False
   Writer.omitXMLDeclaration = True: Writer.Encoding = "utf-8"

   Set Reader.contentHandler = Writer: Set Reader.dtdHandler = Writer
   Set Reader.errorHandler = Writer

   Call Reader.putProperty("http://xml.org/sax/properties/declaration-handler", Writer)
   Call Reader.putProperty("http://xml.org/sax/properties/lexical-handler", Writer)
   Call Reader.parse(XML) 'A document must contain exactly one root element
   PrettyPrintXML = Writer.output
 End Function
  • 要检查是否需要更改,您可以验证:x1米11米1x

相关问题