Durchsuchbare Dokumentation aufrufen

Zurück zur Dokumentationsübersicht

JavaScript-Bibliothek common/xml

Diese Bibliothek bietet Funktionen zum Parsen oder Ausführen von XML-Dateien (agoscript) oder zum Parsen oder Erstellen allgemeingültiger XML-Dateien.

Verwendung


Binden Sie die Bibliothek stets am Anfang eines Skripts ein:

let xml = require('common/xml');

Funktionen


read()

Liest XML-Dateien aus.


A​ufruf

let xml = require('common/xml');
let objects = require('common/objects');

let obj = objects.find('id oder Pfad eines XML-Files');
let result = xml.read(obj);


Rückgabewert

Sie erhalten eine Objektstruktur, die Sie direkt in JavaScript lesen können.

Hinweis: Neben Objekten akzeptiert die Funktion auch Streams und Strings. Bei letzteren ist der Aufrufer selbst dafür verantwortlich, eventuelle Eingangsdaten im korrekten Encoding zu lesen.


Beispiel

<test>
  <knoten1>Inhalt 1</knoten1>
  <knoten2 attr1="Inhalt Attr 1">Inhalt 2</knoten2>
  <knoten3 attr2="Inhalt Attr 2">
    <knoten3sub>Inhalt 3.1</knoten3sub>
    <knoten3sub>Inhalt 3.2</knoten3sub>
    <knoten3sub>Inhalt 3.3</knoten3sub>
  </knoten3>
  <knoten4 attr3="Inhalt Attr 3">
    <knoten4sub1>Inhalt 4.1</knoten4sub1>
    <knoten4sub2>Inhalt 4.1</knoten4sub2>
  </knoten4>
</test>


Ergebnis

{
  "test": {
    "knoten1": "Inhalt 1",
    "knoten2": {
      "~attr1": "Inhalt Attr 1",
      "#text": "Inhalt 2"
    },
    "knoten3": {
      "~attr2": "Inhalt Attr 2",
      "knoten3sub": [
        "Inhalt 3.1",
        "Inhalt 3.2",
        "Inhalt 3.3"
      ]
    },
    "knoten4": {
      "~attr3": "Inhalt Attr 3",
      "knoten4sub1": "Inhalt 4.1",
      "knoten4sub2": "Inhalt 4.1"
    }
  }
}

run()

Führt agoscript-Skripte aus.


Rückgabewerte

Sie erhalten die in dem jeweiligen Skript definierten XmlReturn-Werte.


Beispiel

let xml = require('common/xml');
let objects = require('common/objects');

let script = objects.find('/agorum/roi/customers/test/xml/test.xml');
let folder = objects.find('/agorum/roi/Files/test');

// führt das script test.xml im Kontext des Ordners /agorum/roi/Files/test aus
xml.run(script, folder);

Der zweite Parameter für den Ordner ist optional. Wird er nicht angegeben, wird stattdessen der Root-Ordner als Kontext verwendet.

parse()

Wandelt allgemeingültige XML-Dateien und Strukturen in ein für JavaScript angenehmes Format.


Rückgabewerte

Sie erhalten eine JavaScript-Objektstruktur mit den Inhalten der geparsten XML-Struktur.


Parameter

Parameter Beschreibung
source Definiert einen String, ein agorum core-Objekt oder ein Stream, der die XML-Daten enthält.
parameters (optional) Definiert zusätzliche Parameter als Parameter-Objekt.
// Liste der verfügbaren Parameter
let parameters = {
  ignoreNamespaces: true  // deaktiviert die Validierung der XML-Namespaces
}


Beispiel

let xml = require('common/xml');
xml.parse('<CdataTest><xyz><![CDATA[vor innerem cdata <![CDATA[test]]]]><![CDATA[> nach innerem cdata]]></xyz></CdataTest>');


Ergebnis

{
  children: [
    {
      children: [],
      name: 'xyz',
      attributes: [],
      type: 'ElementNode',
      value: 'vor innerem cdata <![CDATA[test]]> nach innerem cdata'
    }
  ],
  name: 'CdataTest',
  attributes: [],
  type: 'ElementNode'
}

streamify()

Überführt eine XML-JavaScript-Struktur in eine gültige XML-Struktur.

Die Übergabe erfolgt als JavaScript-Struktur.


Rückgabewerte

Sie erhalten einen InputStream, der dazu verwendet werden kann, um direkt in Dateien schreiben zu können oder APIs anzusprechen.


Beispiel

let xml = require('common/xml');
xml.stringify({
  children: [
    {
      children: [],
      name: 'xyz',
      attributes: [],
      type: 'ElementNode',
      value: 'vor innerem cdata <![CDATA[test]]> nach innerem cdata'
    }
  ],
  name: 'CdataTest',
  attributes: [],
  type: 'ElementNode'
}, {forceCDATA: true}); // optionaler Parameter, siehe folgende Tabelle


Parameter

Parameter Beschreibung
forceCDATA true
Legt für jeden Wert, der in das XML geschrieben wird, einen CDATA-Bereich an (etwa bei value).

false (Standard)
Legt keine CDATA-Bereiche in den XML-Werten an.

stringify()

Überführt eine XML-JavaScript-Struktur in eine gültige XML-Struktur. 

Die Übergabe erfolgt als JavaScript-Struktur.

Hinweis: Sie müssen zuvor die Funktion parse() angewandt haben, um das XML in eine gültige XML-Struktur zu überführen. Die Funktion read() gibt lediglich eine simple Struktur des XML zurück, die zwar ausreicht, um die Daten zu extrahieren, jedoch nicht, um diese zuverlässig zurück zu überführen.


Rückgabewerte

Sie erhalten einen String mit einer gültigen XML-Struktur.


Beispiel

let xml = require('common/xml');
xml.stringify({
  children: [
    {
      children: [],
      name: 'xyz',
      attributes: [],
      type: 'ElementNode',
      value: 'vor innerem cdata <![CDATA[test]]> nach innerem cdata'
    }
  ],
  name: 'CdataTest',
  attributes: [],
  type: 'ElementNode'
}, {forceCDATA: true}); // optionaler Parameter, siehe folgende Tabelle


Parameter

Parameter Beschreibung
forceCDATA  true
Legt für jeden Wert, der in das XML geschrieben wird, einen CDATA-Bereich an (etwa bei value).

false (Standard)
Legt keine CDATA-Bereiche in den XML-Werten an.


Ergebnis

Mit Parameter forceCDATA auf true:

<?xml version="1.0" encoding="UTF-8"?><CdataTest><xyz><![CDATA[vor innerem cdata <![CDATA[test]]]]><![CDATA[> nach innerem cdata]]></xyz></CdataTest>

Ohne Parameter forceCDATA oder auf false:

<?xml version="1.0" encoding="UTF-8"?><CdataTest><xyz>vor innerem cdata &lt;![CDATA[test]]&gt; nach innerem cdata</xyz></CdataTest>

XML-JavaScript-Struktur


Die Methoden parse(), streamify() und stringify() arbeiten mit der XML-JavaScript-Struktur. Die Struktur abstrahiert eine XML-Struktur auf eine in JavaScript verwendbare Objektnotation. Auf dieser Objektnotation kann ein JavaScript durch die Informationen des XML traversieren und gegebenenfalls manipulieren.

Die Struktur besitzt ein bestimmtes Format, das an dieser Stelle näher erläutert wird.

Allgemeines Format der verschiedenen Bausteine


Das Format für die verschiedenen Bausteine innerhalb der Struktur ist grundsätzlich gleich. Die Bausteine unterscheiden sich lediglich in der Interpretation des Formats bei der Erzeugung der XML-Struktur oder wenn das Format aus der XML-Struktur erzeugt wurde:

Format Beschreibung
name Definiert den Namen der Struktur oder des Tags innerhalb der XML-Struktur.

Der Name muss den allgemeinen Richtlinien für Tags innerhalb von XML-Strukturen entsprechen.
type Definiert den Typ der Struktur oder des Bausteins.

Wenn Sie den Typ des Bausteins nicht angeben, geht die Bibliothek davon aus, dass es sich um eine Element-Node handelt.
value Definiert den geltenden Wert für den Baustein.

Nähere Einschränkungen und Beschreibung zur Verwendung des values finden Sie in den Beschreibungen der Bausteine.
attributes Definiert Attribute für den Baustein, die in der XML-Struktur ebenfalls als Attribute auf Tag-Ebene zu finden sind.

Die Definition der Attribute ist ein Array bestehend aus einer Objektnotation, die name und value enthält.
{
  name: 'Name des Attributes',
  value: 'Value des Attributes'
}
children Definiert ein Array aus weiteren Bausteinen oder Knotendefinitionen, um die weitere Struktur der XML-Struktur zu repräsentieren.

Bausteine verwenden und kombinieren


Die folgenden Bausteine können Sie in der Struktur verwenden und kombinieren.

Element-Node

Ein Element-Node ist ein allgemeiner Knoten, der verwendet werden kann, um:

Ein Element-Node ist der Standard, wenn kein Typ in der Struktur angegeben wird.

Der Element-Node kann weitere Nodes zugewiesen werden. Diese müssen im Schlüssel children hinterlegt werden.

Wenn die Node Attribute besitzen soll, können diese über den Schlüssel attributes der Node zugewiesen werden.

Der Typ der Element-Node ist als Konstante in der Bibliothek verfügbar und kann über den Wert ELEMENT_NODE verwendet werden.

{
  name: 'ElementNode',
  type: xml.ELEMENT_NODE,
  value: 'Wert 123',
  attributes: [],
  children: []
}

Processing-Instruction-Node

Ein Proccesing-Instruction-Node ist ein Knoten, der einer XML-Struktur weitere Parsing und Verarbeitungsinformationen hinterlegt. Dieser Knoten hat bei der Erstellung der XML-Struktur keine direkte Auswirkung auf die Erstellung, jedoch Auswirkung in dem Bereich, in dem die XML-Struktur geparst und interpretiert wird. Das Format des values einer Processing-Instruction-Node ist frei wählbar und abhängig vom gewählten Anwendungsfall.

Der Typ der Element-Node ist als Konstante in der Bibliothek verfügbar und kann über den Wert PROCESSING_INSTRUCTION_NODE verwendet werden.

{
  name: 'ProcessingInstructionNode',
  type: xml.PROCESSING_INSTRUCTION_NODE,
  value: 'id="abc"',
  attributes: []
}

Comment-Node

Ein Comment-Node ist ein Knoten, der einer XML-Struktur ein Kommentar hinzufügt.

Der Typ der Element-Node ist als Konstante in der Bibliothek verfügbar und kann über den Wert COMMENT_NODE verwendet werden.

{
  name: 'CommentNode',
  type: xml.COMMENT_NODE,
  value: 'Kommentar'
}

Document-Fragment-Node

Ein Document-Fragment-Node stellt einen Root-Knoten für XML-Strukturen dar, die nicht der allgemeingültigen XML-Struktur entsprechen. Hauptsächlich handelt es sich hier um XML-Strukturen, die in andere XML-Strukturen integriert werden sollen oder allgemein um XML-Strukturen, die nicht als eigenständige Struktur verwendet werden möchten. Die Document-Fragment-Node wird bei der Generierung nicht in die XML-Struktur übernommen, sondern vielmehr durch die sich unterhalb des Parameter children befindlichen Struktur ersetzt. Wird die Document-Fragment-Node als Root-Knoten verwendet, wird auch keine Präambel mit <xml>...: erzeugt.

Der Typ der Document-Fragment-Node ist als Konstante in der Bibliothek verfügbar und kann über den Wert DOCUMENT_FRAGMENT_NODE verwendet werden.

{
  name: 'DocumentFragmentNode',
  type: xml.DOCUMENT_FRAGMENT_NODE,
  children: []
}

Anwendungsbeispiele


Attributen zu einer Node hinzufügen

{
  name: 'ElementNode',
  type: xml.ELEMENT_NODE,
  attributes: [
    {
      name: 'AttributeName1',
      value: 'AttributeValue1'
    },
    {
      name: 'AttributeName2',
      value: 'AttributeValue2'
    }
  ]
}

Text- oder CDATA-Node erstellen

{
  name: 'MyTextValue',
  type: xml.ELEMENT_NODE,
  value: 'MyValue'
}

Einfache Struktur mit einer oder mehreren Text- oder CDATA-Nodes erstellen

{
  name: 'MyElementNode',
  type: xml.ELEMENT_NODE,
  children: [
    {
      name: 'MyTextValue1',
      type: xml.ELEMENT_NODE,
      value: 'MyValue1'
    },
    {
      name: 'MyTextValue2',
      type: xml.ELEMENT_NODE,
      value: 'MyValue2'
    }
  ]
}

Struktur mit einer Document-Fragment-Node erstellen

{
  type: xml.DOCUMENT_FRAGMENT_NODE,
  children: [
    {
      name: 'ElementNode',
      type: xml.ELEMENT_NODE,
      children: [
        {
          name: 'MyTextValue1',
          type: xml.ELEMENT_NODE,
          value: 'MyValue1'
        }
      ]
    },
    {
      name: 'MyTextValue2',
      type: xml.ELEMENT_NODE,
      value: 'MyValue2'
    }
  ]
}

XML aus der REDDOXX-Schnittstelle

<?xml version="1.0" encoding="UTF-8"?>
<Reddoxx>
  <TRdxExportMetadata>
    <Id>1A540A0DC2AD4127BC551A44614FB1A71DCE5D5F</Id>
    <IndexAlias>{851235E9-F1F9-49D7-9BA0-D0E560F4248F}</IndexAlias>
    <Subject>Re:AW: [CISS] Re:Unser Gespräch am 23.07.2010</Subject>
    <MessageId>&lt;32734840.15902.1280213625807.JavaMail.root@agamd01&gt;</MessageId>
    <InReplyToId>&lt;20100726215326718DNB@reddoxx.com&gt;</InReplyToId>
    <Sender>Oliver Schulze &lt;oliver.schulze@agorum.com&gt;</Sender>
    <Score>0</Score>
    <AttachmentNameList Count="0"></AttachmentNameList>
    <AttachmentSizeList Count="0"></AttachmentSizeList>
    <ToRecipients Count="1">
      <L0>Andreas Dannenberg &lt;andreas.dannenberg@reddoxx.com&gt;</L0>
    </ToRecipients>
    <CcRecipients Count="0">
    </CcRecipients>
    <BccRecipients Count="0"></BccRecipients>
    <Size>1129860</Size>
    <Date>2010-07-27 08:53:45</Date>
    <ArchiveStamp>2010-07-27 08:54:00</ArchiveStamp>
    <StoreStamp>2010-07-27 08:54:50</StoreStamp>
    <MessageType>1</MessageType>
    <Encryption>0</Encryption>
    <Direction>2</Direction>
    <State>0</State>
    <EnvRecipients Count="1">
      <L0>andreas.dannenberg@reddoxx.com</L0>
    </EnvRecipients>
    <EnvSender>oliver.schulze@agorum.com</EnvSender>
    <Spam>0</Spam>
  </TRdxExportMetadata>
</Reddoxx>

 Ergebnis von var result = xml.read(obj);

{
  "Reddoxx": {
    "TRdxExportMetadata": {
      "ArchiveStamp": "2010-07-27 08:54:00",
      "InReplyToId": "<20100726215326718DNB@reddoxx.com>",
      "Size": "1129860",
      "ToRecipients": {
        "L0": "Andreas Dannenberg <andreas.dannenberg@reddoxx.com>",
        "~Count": "1"
      },
      "EnvRecipients": {
        "L0": "andreas.dannenberg@reddoxx.com",
        "~Count": "1"
      },
      "Encryption": "0",
      "Direction": "2",
      "IndexAlias": "{851235E9-F1F9-49D7-9BA0-D0E560F4248F}",
      "Subject": "Re:AW: [CISS] Re:Unser Gespräch am 23.07.2010",
      "Date": "2010-07-27 08:53:45",
      "Spam": "0",
      "Sender": "Oliver Schulze <oliver.schulze@agorum.com>",
      "Score": "0",
      "CcRecipients": {
        "~Count": "0"
      },
      "AttachmentNameList": {
        "~Count": "0"
      },
      "EnvSender": "oliver.schulze@agorum.com",
      "BccRecipients": {
        "~Count": "0"
      },
      "State": "0",
      "Id": "1A540A0DC2AD4127BC551A44614FB1A71DCE5D5F",
      "AttachmentSizeList": {
        "~Count": "0"
      },
      "StoreStamp": "2010-07-27 08:54:50",
      "MessageType": "1",
      "MessageId": "<32734840.15902.1280213625807.JavaMail.root@agamd01>"
    }
  }
}

Programm, um die Daten aus der XML-Datei als Metadaten zu belegen

In diesem Beispiel werden die Metadaten auf das XML-Objekt selbst gesetzt:

/* global sc */ 

let objects = require('common/objects');
let beans = require('common/beans');
let metadata = require('filingassistant/metadata');

// ID auf die xml-Datei
let obj = objects.find('13645631');

let xml = require('common/xml');

let result = xml.read(obj);

setMetaData(obj, result);

function setMetaData(obj, xml) {
  let data = {};
  // Bereich "Reddoxx" auslesen
  let reddoxx = xml.Reddoxx;
  // Aus dem Bereich "Reddoxx" jetzt den Bereich "TRdxExportMetadata" auslesen
  let TRdxExportMetadata = reddoxx.TRdxExportMetadata;
  
  // Jetzt alle Metadaten aus dem Bereich "TRdxExportMetadata" auslesen
  data.reddoxx_archiveStamp             = toDate(TRdxExportMetadata.ArchiveStamp);
  data.reddoxx_inReplyToId              = isEmpty(TRdxExportMetadata.InReplyToId);  
  data.reddoxx_size                     = isEmpty(TRdxExportMetadata.Size);
  data.reddoxx_toRecipients             = toArray(TRdxExportMetadata.ToRecipients, TRdxExportMetadata.ToRecipients['~Count']);
  data.reddoxx_toRecipientsCount        = TRdxExportMetadata.ToRecipients['~Count'];
  data.reddoxx_envRecipients            = toArray(TRdxExportMetadata.EnvRecipients, TRdxExportMetadata.EnvRecipients['~Count']);
  data.reddoxx_envRecipientsCount       = TRdxExportMetadata.EnvRecipients['~Count'];
  data.reddoxx_encryption               = isEmpty(TRdxExportMetadata.Encryption);
  data.reddoxx_direction                = isEmpty(TRdxExportMetadata.Direction);
  data.reddoxx_indexAlias               = isEmpty(TRdxExportMetadata.IndexAlias);
  data.reddoxx_subject                  = isEmpty(TRdxExportMetadata.Subject);
  data.reddoxx_date                     = toDate(TRdxExportMetadata.Date);
  data.reddoxx_spam                     = isEmpty(TRdxExportMetadata.Spam);
  data.reddoxx_sender                   = isEmpty(TRdxExportMetadata.Sender);
  data.reddoxx_score                    = isEmpty(TRdxExportMetadata.Score);
  data.reddoxx_ccRecipients             = toArray(TRdxExportMetadata.CcRecipients, TRdxExportMetadata.CcRecipients['~Count']);
  data.reddoxx_ccRecipientsCount        = TRdxExportMetadata.CcRecipients['~Count'];
  data.reddoxx_attachmentNameList       = toArray(TRdxExportMetadata.AttachmentNameList, TRdxExportMetadata.AttachmentNameList['~Count']);
  data.reddoxx_attachmentNameListCount  = TRdxExportMetadata.AttachmentNameList['~Count'];
  data.reddoxx_envSender                = isEmpty(TRdxExportMetadata.EnvSender);
  data.reddoxx_state                    = isEmpty(TRdxExportMetadata.State);
  data.reddoxx_id                       = isEmpty(TRdxExportMetadata.Id);
  data.reddoxx_attachmentSizeList       = toArray(TRdxExportMetadata.AttachmentSizeList, TRdxExportMetadata.AttachmentSizeList['~Count']);
  data.reddoxx_attachmentSizeListCount  = TRdxExportMetadata.AttachmentSizeList['~Count'];
  data.reddoxx_storeStamp               = toDate(TRdxExportMetadata.StoreStamp);
  data.reddoxx_messageType              = isEmpty(TRdxExportMetadata.MessageType);
  data.reddoxx_messageId                = isEmpty(TRdxExportMetadata.MessageId);
  
 // metadata(data).save(obj);
  return data; 
}

function toDate(datestr) {
  // 2010-07-24 10:35:40
  let da = datestr.split('-').join(' ').split(':').join(' ').split(' ');
  return new Date(da[0], da[1]-1, da[2], da[3], da[4], da[5]);
}

function toArray(obj, count) {
  let array = [];
  for (var i = 0; i < count; i++) {
    array[i] = obj['L' + i];
  }
  return array;
}

function isEmpty(obj) {

    // null and undefined are "empty"
    if (obj === null) return null;

    // Assume if it has a length property with a non-zero value
    // that that property is correct.
    if (obj.length > 0)    return obj;
    if (obj.length === 0)  return null;

    // If it isn't an object at this point
    // it is empty, but it can't be anything *but* empty
    // Is it empty?  Depends on your application.
    if (typeof obj !== "object") return null;

    // Otherwise, does it have any properties of its own?
    // Note that this doesn't handle
    // toString and valueOf enumeration bugs in IE < 9
    for (var key in obj) {
        if (hasOwnProperty.call(obj, key)) return obj;
    }

    return null;
}