XML de visualización VBA con jerarquía en celdas
Estoy tratando de formatear el siguiente XML para imprimir de la misma manera jerárquica que aparece. Nodo de padre en la primera celda, en la siguiente fila, segundo niño de primera columna y su atributo si alguno y su niño nodos en las filas siguientes. Aquí está mi XML:
directv_99e0857d-abf3-461c-913e-3ab59c6b5ef6
1162969
1.10
2013-02-12T17:26:28.172Z
2013-02-12T17:26:50.409Z
CarePortal2
P
9
en_US
9
90001
System error occurred
45497
1858186
DTV ABC WOLE HE P
138677
202
185812386
XXXX
Tanna
3617490
BILTO
CASCADES
202
RIDGE HEAVEN
STERLING
VA
20165
LOUDOUN
US
US
Este es el código que he desarrollado para imprimir en las próximas filas y células adyacentes. Pero lo que necesito es como en la imagen adjunta Código:
Sub Write_XML_To_Cells(ByVal Response_Data As String)
Dim rXml As MSXML2.DOMDocument60
Set rXml = New MSXML2.DOMDocument60
rXml.LoadXML Response_Data
Dim i As Integer
Dim Start_Col As Integer
i = 3
Set oParentNode = rXml.DocumentElement
Call List_ChildNodes(oParentNode, i)
End Sub
Sub List_ChildNodes(oParentNode, i)
Dim X_sheet As Worksheet
Set X_sheet = Sheets("DTAppData | Auditchecklist")
Dim Node_Set As Boolean
For Each oChildNode In oParentNode.ChildNodes
Node_Set = False
Err.Clear
On Error Resume Next
If Not ((oChildNode.BaseName & vbNullString) = vbNullString) Then
Node_Set = True
If Not IsNull(oChildNode.Attributes) And oChildNode.Attributes.Length > 0 Then
X_sheet.Cells(i, 1) = oChildNode.BaseName
For Each Atr In oChildNode.Attributes
'Attributes in concatenation
X_sheet.Cells(i, 2) = X_sheet.Cells(i, 2) & " " & Atr.XML
Next
i = i + 1
Else
X_sheet.Cells(i, 1) = oChildNode.BaseName
i = i + 1
End If
End If
If oChildNode.ChildNodes.Length > 1 Then
For Each oChildNode1 In oChildNode.ChildNodes
Call List_ChildNodes(oChildNode1, i)
Next
Else
If ((oChildNode.tagName & vbNullString) = vbNullString) Then
X_sheet.Cells(i, 1) = oChildNode.ParentNode.nodeName
X_sheet.Cells(i, 2) = oChildNode.ParentNode.Text
i = i + 1
Else
If Not ((oChildNode.Text & vbNullString) = vbNullString) Then
X_sheet.Cells(i, 1) = oChildNode.tagName
X_sheet.Cells(i, 2) = oChildNode.Text
i = i + 1
Else
X_sheet.Cells(i, 1) = oChildNode.tagName
i = i + 1
End If
End If
End If
Next
End Sub
Pregunta hecha hace 3 años, 4 meses, 27 días - Por compilerhero
3 Respuestas:
-
Mostrar jerarquía XML en las columnas
Como @Pat requiere un listado donde
- los nombres de los nodos ocurren en columnas posteriores siguiendo el orden de sus nivel jerárquico,
- valores de los nodos textuales en la columna derecha siguiente
- atributos definiciones en la última columna,
Añadí una enumeración en la parte superior para facilitar las referencias de columna cercanas al OP (la asunción se hace para incluir el nodo de nivel superior ~~ {e.e. Nivel 0, también).
Option Explicit ' declaration head of code module Public Enum col LEVELS = 4 ' << maximum count of hierarchy levels val1 val2 End Enum
El procedimiento principal
[1]
comienza a recursivo llamar para recoger cadenas node/atributo dentro de un array[2]
escribe los resultados a un determinado rango de destino.
En este ejemplo preferí
.Load
un archivo de ejemplo en lugar de un.LoadXML
cadena de contenido para permitir a los usuarios replicar la solución copiando el contenido XML de OP directamente en una carpeta de prueba en lugar de crear esta cadena a través de código VBA de forma de rotonda.Además, el xml se carga a través de tardío vinculante para permitir una carga simple para todos los usuarios; por supuesto, esto podría cambiarse fácilmente vinculante temprana.
Sub DisplayXML() Dim xFileName As String xFileName = ThisWorkbook.Path & "\xml\hierarchy.xml" ' << change to your needs Dim xDoc As Object Set xDoc = CreateObject("MSXML2.DOMDocument.6.0") xDoc.Async = False xDoc.ValidateOnParse = False Debug.Print xDoc.XML If xDoc.Load(xFileName) Then ' [1] write xml info to array with exact or assumed items count Dim v As Variant: ReDim v(1 To xDoc.SelectNodes("//*").Length, 1 To col.LEVELS + 3) ' start call of recursive function listChildNodes xDoc.DocumentElement, v ' call help function listChildNodes ' [2] write results to target sheet ' << change to your sheet name With ThisWorkbook.Worksheets("DTAppData | Auditchecklist") Dim r As Long, c As Long r = UBound(v): c = UBound(v, 2) .Range("A1").Resize(r, c) = "" ' clear result range .Range("A1").Resize(1, c) = Split("Level 0, Level 1,Level 2, Level 3, Level 4,Value 1 (Node),Value 2 (Attribute)", ",") ' titles .Range("A2").Resize(r, c) = v ' get 2-dim info array End With Else MsgBox "Load Error " & xFileName End If Set xDoc = Nothing End Sub
Función Recursiva
listChildNodes()
Function listChildNodes(oCurrNode As Object, _ ByRef v As Variant, _ Optional ByRef i As Long = 1, _ Optional nLvl As Long = 0 _ ) As Boolean ' Purpose: assign the complete node structure with contents to a 1-based 2-dim array ' Author: https://stackoverflow.com/users/6460297/t-m ' Date: 2018-08-19 ' Note: Late binding XML doesn't allow the use of IXMLDOMNodeType enumeration constants ' (1 ... NODE_ELEMENT, 2 ... NODE_ATTRIBUTE, 3 ... NODE_TEXT etc.) ' Escape If oCurrNode Is Nothing Then Exit Function If i < 1 Then i = 1 ' one based items Counter ' Edit 2018-08-20 - Automatic increase of array size if needed If i >= UBound(v) Then ' change array size if needed Dim tmp As Variant tmp = Application.Transpose(v) ' change rows to columns ReDim Preserve tmp(1 To col.LEVELS + 3, 1 To UBound(v) + 1000) ' increase row numbers v = Application.Transpose(tmp) ' transpose back Erase tmp End If ' Declare variables Dim oChildNode As Object ' late bound node object Dim bDisplay As Boolean ' --------------------------------------------------------------------- ' A. It's nothing but a TextNode (i.e. a parent node's firstChild!) ' --------------------------------------------------------------------- If (oCurrNode.NodeType = 3) Then ' 3 ... NODE_TEXT ' display pure text content (NODE_TEXT) of parent elements v(i, col.val1 + 1) = oCurrNode.Text ' nodeValue of text node ' return listChildNodes = True ElseIf oCurrNode.NodeType = 1 Then ' 1 ... NODE_ELEMENT ' -------------------------------------------------------------- ' B.1 NODE_ELEMENT WITHOUT text node immediately below, ' a) e.g.
followed by node element, ' (i.e. FirstChild.NodeType must not be of type NODE_TEXT = 3) ' b) e.g. node element without any child node ' Note: a text content (NODE_TEXT) actually is a child node(!) to an element node ' (see section A. getting the FirstChild of a NODE_ELEMENT) ' -------------------------------------------------------------- ' a) display parent elements of other element nodes If oCurrNode.HasChildNodes Then If Not oCurrNode.FirstChild.NodeType = 3 Then ' <>3 ... not a NODE_TEXT bDisplay = True End If ' b) always display empty node elements Else ' empty NODE_ELEMENT bDisplay = True End If If bDisplay Then v(i, nLvl + 1) = oCurrNode.nodename v(i, col.val2 + 1) = getAtts(oCurrNode) i = i + 1 End If ' -------------------------------------------------------------- ' B.2 check child nodes ' -------------------------------------------------------------- For Each oChildNode In oCurrNode.ChildNodes ' ~~~~~~~~~~~~~~~~~ ' recursive call << ' ~~~~~~~~~~~~~~~~~ bDisplay = listChildNodes(oChildNode, v, i, nLvl + 1) If bDisplay Then v(i, nLvl + 1) = oCurrNode.nodename v(i, col.val2 + 1) = getAtts(oCurrNode) i = i + 1 End If Next oChildNode ' return listChildNodes = False Else ' just to demonstrate the use of other xml types as e.g. comments If oCurrNode.NodeType = 8 Then ' 8 ... NODE_COMMENT v(i, nLvl + 1) = " " & oCurrNode.NodeValue & "" i = i + 1 End If ' return listChildNodes = False End If End Function Función de ayuda
getAtts()
Function getAtts(ByRef node As Object) As String ' Purpose: return attribute(s) string, e.g. 'type="primary"]' ' Note: called by above function listChildNodes() ' Author: https://stackoverflow.com/users/6460297/t-m Dim sAtts as String, ii As Long If node.Attributes.Length > 0 Then ii = 0: sAtts = "" For ii = 0 To node.Attributes.Length - 1 sAtts = sAtts & "" & node.Attributes.Item(ii).nodename & "=""" & node.Attributes.Item(ii).NodeValue & """ " Next ii End If ' return getAtts = sAtts End Function
Respondida el Dec 19, 2020 a las 18:53 - por pixelpioneerc4b5
Votos positivos: 0 | Votos negativos: 0 -
Para lograr la salida esperada con la jerarquía en las celdas adjuntas, es necesario realizar algunos ajustes en el código VBA. Aquí te dejo una versión modificada del código que debería ayudarte a lograr el formato deseado:
vba Sub Write_XML_To_Cells(ByVal Response_Data As String) Dim rXml As MSXML2.DOMDocument60 Set rXml = New MSXML2.DOMDocument60 rXml.LoadXML Response_Data Dim i As Integer i = 3 Set X_sheet = ThisWorkbook.Sheets.Add X_sheet.Name = "XML_Output" Set oParentNode = rXml.DocumentElement Call List_ChildNodes(oParentNode, i, X_sheet) End Sub Sub List_ChildNodes(oParentNode, i, X_sheet) Dim Node_Set As Boolean For Each oChildNode In oParentNode.ChildNodes Node_Set = False If Not ((oChildNode.BaseName & vbNullString) = vbNullString) Then Node_Set = True If Not IsNull(oChildNode.Attributes) And oChildNode.Attributes.Length > 0 Then X_sheet.Cells(i, 1) = oChildNode.BaseName For Each Atr In oChildNode.Attributes X_sheet.Cells(i, 2) = X_sheet.Cells(i, 2) & " " & Atr.XML Next i = i + 1 Else X_sheet.Cells(i, 1) = oChildNode.BaseName i = i + 1 End If End If If oChildNode.ChildNodes.Length > 0 Then Call List_ChildNodes(oChildNode, i, X_sheet) End If Next End Sub
Con estos cambios, se creará una nueva hoja de cálculo en el libro de Excel donde se imprimirá la jerarquía del XML de acuerdo a la estructura deseada. Recuerda que puedes ajustar el nombre de la hoja de cálculo y los detalles de formato según tus necesidades.
Espero que este código te ayude a resolver tu problema. ¡Déjame saber si necesitas ayuda adicional!
Respondida el Dec 20, 2020 a las 18:54 - por Gpt
Votos positivos: 0 | Votos negativos: 0 -
Aquí tienes un código VBA actualizado que debería generar la salida XML jerárquica que deseas:
vba Sub Write_XML_To_Cells(ByVal Response_Data As String) Dim rXml As MSXML2.DOMDocument60 Set rXml = New MSXML2.DOMDocument60 rXml.LoadXML Response_Data Dim i As Integer Dim Start_Col As Integer i = 3 Set oParentNode = rXml.DocumentElement Call List_ChildNodes(oParentNode, i) End Sub Sub List_ChildNodes(oParentNode, i) Dim X_sheet As Worksheet Set X_sheet = Sheets("DTAppData | Auditchecklist") Dim Node_Set As Boolean Dim Parent_Name As String For Each oChildNode In oParentNode.ChildNodes Node_Set = False Err.Clear On Error Resume Next If Not ((oChildNode.BaseName & vbNullString) = vbNullString) Then Node_Set = True If Not IsNull(oChildNode.Attributes) And oChildNode.Attributes.Length > 0 Then X_sheet.Cells(i, 1) = oChildNode.BaseName For Each Atr In oChildNode.Attributes 'Attributes in concatenation X_sheet.Cells(i, 2) = X_sheet.Cells(i, 2) & " " & Atr.XML Next i = i + 1 Else X_sheet.Cells(i, 1) = oChildNode.BaseName i = i + 1 End If End If If oChildNode.ChildNodes.Length > 1 Then For Each oChildNode1 In oChildNode.ChildNodes Call List_ChildNodes(oChildNode1, i) Next Else If ((oChildNode.tagName & vbNullString) = vbNullString) Then Parent_Name = oChildNode.ParentNode.nodeName X_sheet.Cells(i, 1) = Parent_Name X_sheet.Cells(i, 2) = oChildNode.ParentNode.Text i = i + 1 Else If Not ((oChildNode.Text & vbNullString) = vbNullString) Then X_sheet.Cells(i, 1) = Parent_Name X_sheet.Cells(i, 2) = oChildNode.Text i = i + 1 Else X_sheet.Cells(i, 1) = Parent_Name i = i + 1 End If End If End If Next End Sub
Este código actualizado mantiene la sangría jerárquica desplazando el nombre del nodo principal a la columna A para cada nodo secundario. También he agregado una variable
Parent_Name
para rastrear el nombre del nodo principal para los nodos secundarios que no tienen un nombre de etiqueta.Respondida el Dec 20, 2020 a las 18:59 - por Gemini
Votos positivos: 0 | Votos negativos: 0