von preklov » Mo, 10.08.2009 08:48
Hi, Cronus, ich bin zwar beileibe kein Profi, aber da ich sowieso an dem Thema dran bin und nirgends etwas in Starbasic zu finden zu sein scheint, habe ich mal etwas gebastelt.
Du brauchst natürlich zuerst einmal eine Datenquelle. Ich kann mir nur schwer vorstellen, dass Du die aus einer Selektion holen willst, denn der Aufwand ist sicher groß, den Du treiben musst, um auszuschließen, dass die Selektionsdaten nicht kompatibel mit dem benötigten xml-Schema sind. Ich bevorzuge ein Tabellenblatt mit eindeutiger Struktur: 1. Zeile die Feldnamen, jede weitere Zeile ein Datensatz. In diesem calc-Dokument steckt das Makro mit der Datenausgabe in einen DOM-Baum.
Ich habe ein Beispiel erstellt:
http://www.uni-due.de/~abi070/files/OOo/xmltest.ods
Darin wird der DOM-Baum erstellt:
Code: Alles auswählen
oDomBuilder = _
createUnoService("com.sun.star.xml.dom.DocumentBuilder")
oDom = oDocBuilder.newDocument()
Alle Teile der xml-Struktur sind Nodes im DOM. Du musst sie erzeugen und in den Baum einfügen, z.B.:
oder
Einfügen:
Und Du brauchst noch Attribute:
Code: Alles auswählen
oN3.setAttribute(Name_des_Attributs, Wert_des_Attributs)
Mehr ist das eigentlich nicht

Schau Dir die Interfaces auf den API-Seiten an:
http://api.openoffice.org/docs/common/r ... le-ix.html
In der Datei sind auch die benötigten Ausgabeprozeduren. Das ist einmal die Prozedur, die den Output-Stream erzeugt und die Datenausgabe aus dem DOM einleitet:
Code: Alles auswählen
Sub WriteDomToFile(oTree as object, sFilePath as string)
REM Writes the structure of an actual DOM (oTree) line after line
REM into a simple text file.
REM Mark the line feed (LF). It has to be set explicitly.
REM Linux: chr(10), Windows: chr(13) + chr(10)
dim oSimpleFileAccess as object
dim oOutputStream as object
dim oTextOutput as object
dim oTreeNodes as object
dim i as integer
on error goto Catch
LF = chr(10)
REM First set the output stream
sFilePath = converttourl(sFilePath)
oSimpleFileAccess = createUnoService("com.sun.star.ucb.SimpleFileAccess")
with oSimpleFileAccess
if .exists(sFilePath) then .kill(sFilePath)
oOutputStream = .openFileWrite(sFilePath)
end with
oTextOutput = createUnoService("com.sun.star.io.TextOutputStream")
with oTextOutput
.OutputStream = oOutputStream
.setEncoding("UTF-8")
REM The first line is a processing instruction. It usually isn't part of
REM the DOM tree. So we write it separately.
.WriteString("<?xml version=" + chr(34) + "1.0" + chr(34) + "encoding=" _
+ chr(34) + "UTF-8" + chr(34) + "?>" + LF)
REM A DOM tree can consist of zero, one or more child nodes on the
REM root level. They are treated separately.
if oTree.hasChildNodes() then
oTreeNodes = oTree.getChildNodes()
for i = 0 to oTreeNodes.getLength - 1
PrintDom(oTreeNodes.item(i), oTextOutput, 0, 2)
next
end if
.closeOutput()
end with
oOutputStream.closeOutput()
exit sub
Catch:
print "Fehler " + err + " (" + error(err) + ")"
End Sub
Die eigentliche Ausgabe wird durch PrintDom erzeugt, das rekursiv den Elementbaum durchläuft:
Code: Alles auswählen
Sub PrintDom(oElement as object, oStream as object, _
iLevel as integer, iIndent as integer)
REM Writes the elements of a DOM tree recursively line after line into a
REM text file. Mark to start with iLevel 0.
REM Indents lower levels by iIndent characters, except for text nodes: they
REM are written directly after the element start tag followed by the
REM element end tag.
REM It is assumed that there are either one text node or one or more other
REM child nodes to an element, if any.
REM
REM This is a 0.1 version in Starbasic without any validating.
REM Missing: prevent to write parent element tag in case there are child nodes
REM without any content.
REM Please tell me if there already exists some other solution.
REM Please feel free to inform me about errors, improvements and amendments.
REM Author: Volker Lenhardt
REM Email: volker.lenhardt@uni.due.de
dim oElementChildren as object
dim oChild as object
dim sLine as string
dim i as integer
dim iLen as integer
dim sNodeName as string
sNodeName = oElement.getNodeName()
if oElement.getNodeType() = _
com.sun.star.xml.dom.NodeType.COMMENT_NODE then
sLine = string(iLevel * iIndent, " ") + "<!-- " _
+ oElement.getNodeValue() + " -->"
oStream.WriteString(sLine + LF)
elseif oElement.getNodeType() = _
com.sun.star.xml.dom.NodeType.PROCESSING_INSTRUCTION_NODE then
REM Is there a bug? If I create a processing instruction with both
REM the target "xml" and data "version..." arguments, the getTarget
REM yields "xml", but the getData yields "". The only way is to give
REM the whole string as target and "" as data, and to retrieve it as
REM nodename. Can someone reproduce this behaviour?
sLine = string(iLevel * iIndent, " ") + "<?" + sNodeName + "?>"
oStream.WriteString(sLine + LF)
else
sLine = string(iLevel * iIndent, " ") + "<" + sNodeName _
+ AttString(oElement.getAttributes()) + ">"
if oElement.hasChildNodes() then
oElementChildren = oElement.getChildNodes()
iLen = oElementChildren.getLength()
if iLen = 1 then 'Test for text node, assuming that there are no other
' sibling nodes besides.
oChild = oElementChildren.item(0)
if oChild.getNodeType() = com.sun.star.xml.dom.NodeType.TEXT_NODE then
sLine = sLine + oChild.getNodeValue() + _
"</" + sNodeName + ">"
oStream.WriteString(sLine + LF)
exit sub
end if
end if
oStream.WriteString(sLine + LF)
for i = 0 to iLen - 1
PrintDom(oElementChildren.item(i), oStream, iLevel + 1, iIndent)
next
sLine = string(iLevel * iIndent, " ") + "</" + sNodeName + ">"
oStream.WriteString(sLine + LF)
else
REM If there is no child node, but attributes, the short form is used.
REM If there are not even attributes, no element tag is written.
if oElement.hasAttributes() then
sLine = left(sLine, len(sLine) - 1) + " />"
oStream.WriteString(sLine + LF)
end if
end if
end if
End Sub
In der Beispieldatei sind noch ein paar praktische Hilfsprozeduren.
Vielleicht ist es das, was Du brauchst. Probier es einmal aus.
Schöne Grüße
Volker
Hi, Cronus, ich bin zwar beileibe kein Profi, aber da ich sowieso an dem Thema dran bin und nirgends etwas in Starbasic zu finden zu sein scheint, habe ich mal etwas gebastelt.
Du brauchst natürlich zuerst einmal eine Datenquelle. Ich kann mir nur schwer vorstellen, dass Du die aus einer Selektion holen willst, denn der Aufwand ist sicher groß, den Du treiben musst, um auszuschließen, dass die Selektionsdaten nicht kompatibel mit dem benötigten xml-Schema sind. Ich bevorzuge ein Tabellenblatt mit eindeutiger Struktur: 1. Zeile die Feldnamen, jede weitere Zeile ein Datensatz. In diesem calc-Dokument steckt das Makro mit der Datenausgabe in einen DOM-Baum.
Ich habe ein Beispiel erstellt: http://www.uni-due.de/~abi070/files/OOo/xmltest.ods
Darin wird der DOM-Baum erstellt:
[code] oDomBuilder = _
createUnoService("com.sun.star.xml.dom.DocumentBuilder")
oDom = oDocBuilder.newDocument()
[/code]
Alle Teile der xml-Struktur sind Nodes im DOM. Du musst sie erzeugen und in den Baum einfügen, z.B.:
[code]oN3 = oDom.createElement("Anschrift")[/code]
oder
[code]oDom.createTextNode(sCellContent)[/code]
Einfügen:
[code]oN3.appendChild(oN4)[/code]
Und Du brauchst noch Attribute:
[code]oN3.setAttribute(Name_des_Attributs, Wert_des_Attributs)[/code]
Mehr ist das eigentlich nicht ;-)
Schau Dir die Interfaces auf den API-Seiten an:
http://api.openoffice.org/docs/common/ref/com/sun/star/xml/dom/module-ix.html
In der Datei sind auch die benötigten Ausgabeprozeduren. Das ist einmal die Prozedur, die den Output-Stream erzeugt und die Datenausgabe aus dem DOM einleitet:
[code]Sub WriteDomToFile(oTree as object, sFilePath as string)
REM Writes the structure of an actual DOM (oTree) line after line
REM into a simple text file.
REM Mark the line feed (LF). It has to be set explicitly.
REM Linux: chr(10), Windows: chr(13) + chr(10)
dim oSimpleFileAccess as object
dim oOutputStream as object
dim oTextOutput as object
dim oTreeNodes as object
dim i as integer
on error goto Catch
LF = chr(10)
REM First set the output stream
sFilePath = converttourl(sFilePath)
oSimpleFileAccess = createUnoService("com.sun.star.ucb.SimpleFileAccess")
with oSimpleFileAccess
if .exists(sFilePath) then .kill(sFilePath)
oOutputStream = .openFileWrite(sFilePath)
end with
oTextOutput = createUnoService("com.sun.star.io.TextOutputStream")
with oTextOutput
.OutputStream = oOutputStream
.setEncoding("UTF-8")
REM The first line is a processing instruction. It usually isn't part of
REM the DOM tree. So we write it separately.
.WriteString("<?xml version=" + chr(34) + "1.0" + chr(34) + "encoding=" _
+ chr(34) + "UTF-8" + chr(34) + "?>" + LF)
REM A DOM tree can consist of zero, one or more child nodes on the
REM root level. They are treated separately.
if oTree.hasChildNodes() then
oTreeNodes = oTree.getChildNodes()
for i = 0 to oTreeNodes.getLength - 1
PrintDom(oTreeNodes.item(i), oTextOutput, 0, 2)
next
end if
.closeOutput()
end with
oOutputStream.closeOutput()
exit sub
Catch:
print "Fehler " + err + " (" + error(err) + ")"
End Sub
[/code]
Die eigentliche Ausgabe wird durch PrintDom erzeugt, das rekursiv den Elementbaum durchläuft:
[code]Sub PrintDom(oElement as object, oStream as object, _
iLevel as integer, iIndent as integer)
REM Writes the elements of a DOM tree recursively line after line into a
REM text file. Mark to start with iLevel 0.
REM Indents lower levels by iIndent characters, except for text nodes: they
REM are written directly after the element start tag followed by the
REM element end tag.
REM It is assumed that there are either one text node or one or more other
REM child nodes to an element, if any.
REM
REM This is a 0.1 version in Starbasic without any validating.
REM Missing: prevent to write parent element tag in case there are child nodes
REM without any content.
REM Please tell me if there already exists some other solution.
REM Please feel free to inform me about errors, improvements and amendments.
REM Author: Volker Lenhardt
REM Email: volker.lenhardt@uni.due.de
dim oElementChildren as object
dim oChild as object
dim sLine as string
dim i as integer
dim iLen as integer
dim sNodeName as string
sNodeName = oElement.getNodeName()
if oElement.getNodeType() = _
com.sun.star.xml.dom.NodeType.COMMENT_NODE then
sLine = string(iLevel * iIndent, " ") + "<!-- " _
+ oElement.getNodeValue() + " -->"
oStream.WriteString(sLine + LF)
elseif oElement.getNodeType() = _
com.sun.star.xml.dom.NodeType.PROCESSING_INSTRUCTION_NODE then
REM Is there a bug? If I create a processing instruction with both
REM the target "xml" and data "version..." arguments, the getTarget
REM yields "xml", but the getData yields "". The only way is to give
REM the whole string as target and "" as data, and to retrieve it as
REM nodename. Can someone reproduce this behaviour?
sLine = string(iLevel * iIndent, " ") + "<?" + sNodeName + "?>"
oStream.WriteString(sLine + LF)
else
sLine = string(iLevel * iIndent, " ") + "<" + sNodeName _
+ AttString(oElement.getAttributes()) + ">"
if oElement.hasChildNodes() then
oElementChildren = oElement.getChildNodes()
iLen = oElementChildren.getLength()
if iLen = 1 then 'Test for text node, assuming that there are no other
' sibling nodes besides.
oChild = oElementChildren.item(0)
if oChild.getNodeType() = com.sun.star.xml.dom.NodeType.TEXT_NODE then
sLine = sLine + oChild.getNodeValue() + _
"</" + sNodeName + ">"
oStream.WriteString(sLine + LF)
exit sub
end if
end if
oStream.WriteString(sLine + LF)
for i = 0 to iLen - 1
PrintDom(oElementChildren.item(i), oStream, iLevel + 1, iIndent)
next
sLine = string(iLevel * iIndent, " ") + "</" + sNodeName + ">"
oStream.WriteString(sLine + LF)
else
REM If there is no child node, but attributes, the short form is used.
REM If there are not even attributes, no element tag is written.
if oElement.hasAttributes() then
sLine = left(sLine, len(sLine) - 1) + " />"
oStream.WriteString(sLine + LF)
end if
end if
end if
End Sub
[/code]
In der Beispieldatei sind noch ein paar praktische Hilfsprozeduren.
Vielleicht ist es das, was Du brauchst. Probier es einmal aus.
Schöne Grüße
Volker