XML SAX Writer and XAttributeList

Hello all :wink:
I have written the following LO Basic code to write XML via SAX to a file:

Sub WriteXMLwithSAX()
    Dim sFil As String
    sFil = "/tmp/output.xml" ' Change this for your needs
    
    Dim oSFA As Object
    oSFA = CreateUnoService("com.sun.star.ucb.SimpleFileAccess")   
    If oSFA.exists(sFil) Then oSFA.kill(sFil)
    
    Dim oStm As Object
    oStm = oSFA.openFileWrite (sFil)
    
    Dim oSax As Object
    oSax = CreateUnoService ("com.sun.star.xml.sax.Writer")
    oSax.setOutputStream (oStm)

    oSax.startDocument()
    oSax.startElement("TopElement", Null) ' Instead of Null I'd like to
                                          ' use an XAttributeList element
        
    oSax.startElement("ChildElement", Null)
    oSax.characters("ChildValue")
    oSax.endElement("ChildElement")

    oSax.endElement("TopElement")
    oSax.endDocument()

    oStm.closeOutput()
End Sub

This produces a very pretty result “/tmp/output.xml” as expected:

<?xml version="1.0" encoding="UTF-8"?>
<TopElement><ChildElement>ChildValue</ChildElement></TopElement>

However, I’d like to add attributes to the elements “TopElement” and “ChildElement” to obtain e.g. a result like this:

<?xml version="1.0" encoding="UTF-8"?>
<TopElement A="Val1"><ChildElement B="Val2">ChildValue</ChildElement></TopElement>

If I read the LO SDK API correctly, I therefore should use a “XAttributeList” instead of the “Null” that I use above for calls of “startElement()”. “XAttributeList” only has “get…” functions but no “set…” functions and that is why I don’t have any idea how to create a valid “XAttributeList” for the use with “startElement()”. Can someone give me a hint how to create a “XAttributeList”?

Thank you very much.

Well, if you can get the list you can write each element on the list e.g. intoa string…

Private myElements() As String
Sub test
For i = 0 to Elements.Count - 1' for example
myString = myString &  Elements(i)
If i < Elements.Count - 1 Then myString = myString & ","
Next i
myElements = Split(myString, ",")
myString = ""
If Ubound(myElements) > 0 Then Exit Sub

'If you can get the list as a string array it's even easier:
myElements = ArrayContainingAllElements 'and so on...
If Ubound(myElements) > 0 Then Exit Sub
'In the case you get the elements as a dictionary then:

    Dim elementsDict
    Set elementsDict = CreateObject("Scripting.Dictionary")
    For Each element In elemnentsList ' for example
      elementsDict.Add i, element
        i = i + 1
    Next element
    
    Redim myElements(elementsDict.Count - 1)

    For i = 0 To elmentsDict.Count - 1
    	myElemets(i) = elementsDict.ItemIndex(i)
    Next i

End Sub

If it’s a dictionary that includes everything, visit here to see how to populate a readable array from a dictionary

Instead of Windows object CreateObject(“Scripting.Dictionary”) you can use:

	GlobalScope.BasicLibraries.loadLibrary("ScriptForge")
	Dim elementsDict As Variant
	Set elementsDict = CreateScriptService("Dictionary")
	' ...
	' and finally
	Set adaptersDict = adaptersDict.Dispose()

I suspect that we don’t provide a ready-to-use implementation of XAttributeList interface. So you would have to create it yourself. In Basic, you do that using CreateUnoListener function.

' XAttributeList data '
Private AttributeListData As Variant ' when set, should be array of com.sun.star.beans.NamedValue '

' XAttributeList.getLength method '
Function AttributeList_getLength() As Integer
  If Not IsEmpty(AttributeListData) Then
    AttributeList_getLength = UBound(AttributeListData) - LBound(AttributeListData) + 1
  Else
    AttributeList_getLength = 0
  EndIf
End Function

' XAttributeList.getNameByIndex method '
Function AttributeList_getNameByIndex(i As Integer) As String
  ' Assume that AttributeListData is set '
  ' User must not request arbitrary index without checking length first '
  AttributeList_getNameByIndex = AttributeListData(i + LBound(AttributeListData)).Name
End Function

' XAttributeList.getTypeByIndex method '
Function AttributeList_getTypeByIndex(i As Integer) As String
  ' As documented, just return "CDATA" '
  AttributeList_getTypeByIndex = "CDATA"
End Function

' XAttributeList.getTypeByName method '
Function AttributeList_getTypeByName(n As String) As String
  ' As documented, just return "CDATA" '
  AttributeList_getTypeByName = "CDATA"
End Function

' XAttributeList.getValueByIndex method '
Function AttributeList_getValueByIndex(i As Integer) As String
  AttributeList_getValueByIndex = AttributeListData(i + LBound(AttributeListData)).Value
End Function

' XAttributeList.getValueByName method '
Function AttributeList_getValueByName(n As String) As String
  Dim i As Integer
  For i = LBound(AttributeListData) To UBound(AttributeListData)
    If AttributeListData(i).Name = n Then
      AttributeList_getValueByName = AttributeListData(i).Value
      Exit Function
    EndIf
  Next i
End Function

Sub WriteXMLwithSAX()
  ...
  ' Create the attributes object '
  Dim attribs
  attribs = CreateUnoListener("AttributeList_", "com.sun.star.xml.sax.XAttributeList")
  ' Define attributes '
  Dim att As New com.sun.star.beans.NamedValue
  att.Name = "A"
  att.Value = "Val1"
  AttributeListData = array(att)
  oSax.startElement("TopElement", attribs)
  att.Name = "B"
  att.Value = "Val2"
  AttributeListData = array(att)
  oSax.startElement("ChildElement", attribs)
  ...
End Sub
1 Like