Em um projeto em que estou trabalhando, precisamos armazenar alguns XMLs arbitrários no banco de dados. Esse XML não tem nenhuma classe correspondente no IRIS; precisamos apenas armazená-lo como uma string (ele é relativamente pequeno e cabe em uma string).
Como existem MUITOS (milhões!) de registros no banco de dados, decidi reduzir o tamanho o máximo possível sem usar compressão. Sei que parte do XML a ser armazenado está indentada, parte não, isso varia.
Para reduzir o tamanho, decidi minificar o XML, mas como minificar um documento XML no IRIS?
Pesquisei em todas as classes e utilitários e não encontrei nenhum código ou método pronto, então tive que implementar por conta própria, e acabou sendo bem simples no IRIS usando a classe %XML.TextReader, sinceramente, mais simples do que eu esperava.
Como isso pode ser útil em outros contextos, decidi compartilhar esse pequeno utilitário com a Comunidade de Desenvolvedores.
Testei com alguns documentos XML relativamente complexos e funcionou bem, segue o código.
/// Minify an XML document passed in the XmlIn Stream, the minified XML is returned in XmlOut Stream
/// If XmlOut Stream is passed, then the minified XML is stored in the passed Stream, otherwise a %Stream.TmpCharacter in returned in XmlOut.
/// Collapse = 1 (default), empty elements are collapsed, e.g. <tag></tag> is returned as <tag/>
/// ExcludeComments = 1 (default), comments are not returned in the minified XML
ClassMethod MinifyXML(XmlIn As %Stream, ByRef XmlOut As %Stream = "", Collapse As %Boolean = 1, ExcludeComments As %Boolean = 1) As %Status
{
#Include %occSAX
Set sc=$$$OK
Try {
Set Mask=$$$SAXSTARTELEMENT+$$$SAXENDELEMENT+$$$SAXCHARACTERS+$$$SAXCOMMENT
Set sc=##class(%XML.TextReader).ParseStream(XmlIn,.reader,,$$$SAXNOVALIDATION,Mask)
#dim reader as %XML.TextReader
If $$$ISERR(sc) Quit
If '$IsObject(XmlOut) {
Set XmlOut=##class(%Stream.TmpCharacter).%New()
}
While reader.Read() {
Set type=reader.NodeType
If ((type="error")||(type="fatalerror")) {
Set sc=$$$ERROR($$$GeneralError,"Error loading XML "_type_"-"_reader.Value)
Quit
}
If type="element" {
Do XmlOut.Write("<"_reader.Name)
If Collapse && reader.IsEmptyElement {
; collapse empty element
Do XmlOut.Write("/>")
Set ElementEnded=1
} Else {
; add attributes
For k=1:1:reader.AttributeCount {
Do reader.MoveToAttributeIndex(k)
Do XmlOut.Write(" "_reader.Name_"="""_reader.Value_"""")
}
Do XmlOut.Write(">")
}
} ElseIf type="chars" {
Set val=reader.Value
Do XmlOut.Write($select((val["<")||(val[">")||(val["&"):"<![CDATA["_$replace(val,"]]>","]]]]><![CDATA[>")_"]]>",1:val))
} ElseIf type="endelement" {
If $g(ElementEnded) {
; ended by collapsing
Set ElementEnded=0
} Else {
Do XmlOut.Write("</"_reader.Name_">")
}
} ElseIf 'ExcludeComments && (type="comment") {
Do XmlOut.Write("<!--"_reader.Value_"-->")
}
}
} Catch CatchError {
#dim CatchError as %Exception.SystemException
Set sc=CatchError.AsStatus()
}
Quit sc
}
P.S.: Alguém sabe se existe outra forma mais simples de minificar XML no IRIS?













