Anzeige
Tutorialbeschreibung

2. Teil: XML & InDesign Scripting is the key

2. Teil: XML & InDesign Scripting is the key

Dieses Tutorial soll euch zeigen, wie man mithilfe von JavaScript (InDesignskript) und XSL-Transformation XML-Daten in InDesign automatisch verarbeiten kann.

Im zweiten Teil werden wir unsere Daten mithilfe der XSL-Transformatierung formatieren. Zudem die Größe unseres Textfeldes anpassen und unsere XML-Datei erweitern.



Im 2. Teil werden wir uns hauptsächlich mit der XSL-Transformation sowie der Formatierung unserer importierten XML-Datei beschäftigen.

Die Arbeitsdateien beinhalten alle Daten aus dem ersten Teil:

• tutorial_xml.idml
• erste_daten.xml

Neu hinzugekommen:

• zweite_daten.xml
• zweite.xsl
• Bilddatei

sowie die endgültigen Skriptdateien für den Teil 2:

• second_step.jsx (ab CS6)
• alternative_second_step.jsx (ab CS4)

Schauen wir uns noch mal die Struktur unserer XML-Datei aus Teil 1 an sowie die bereits vorhanden Absatzformate in unserer InDesign-Datei.

erste_daten.xml

<?xml version=“1.0“ encoding=“UTF-8“?>
<Bekleidung>
    <produkt>
        <h1>T-shirt</h1>
        <li>Leicht zu tragen</li>
        <li>Färbt nicht ab</li>
        <li>Fair Trade</li>
        <lieferumfang>T-Shirt</lieferumfang>
    </produkt>
</Bekleidung>

Wie ihr seht, habe ich bereits namensgleiche Absatzformate in der InDesign-Datei, um uns das Ganze zu vereinfachen.

li = Aufzählungs-Liste
Lieferumfang = Liste mit dem Wort "Lieferumfang" bei Absatzbeginn
Und ein Tabellenformat Tabelle_h1

Unsere Aufgabe ist es jetzt, InDesign verständlich zu machen, dass die Absatzformate automatisch auf die importierten Daten angewendet werden. Hierzu müssen wir den Tags zusätzlich Attribute hinzufügen. Das Tag <li> zum Beispiel muss später so lauten:

<li aid:pstyle=“li“>

 
Das Attribut aid:pstyle="li" veranlasst InDesign dazu, das Absatzformat "li" anzuwenden.

Erstellt ein Textdokument und benennt es um in "erste.xsl". Achtet darauf, dass ihr UTF-8-Kodierung beim Abspeichern verwendet.

erste.XSL-Datei

<?xml version="1.0" encoding="UTF-8"?>
 <xsl:stylesheet version="2.0"
 xmlns:aid="http://ns.adobe.com/AdobeInDesign/4.0/"
 xmlns:aid5="http://ns.adobe.com/AdobeInDesign/5.0/"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="Bekleidung">
    <root>
          <xsl:apply-templates select="produkt"/>
    </root>
</xsl:template>

<xsl:template match="produkt">
     <textfeld>
              
          <xsl:apply-templates select="li"/>
          <xsl:apply-templates select="lieferumfang"/>
         
     </textfeld>
 </xsl:template>


<xsl:template match="li">
    <li aid:pstyle="li"><xsl:value-of select="." /></li><xsl:text>&#xA;</xsl:text>
</xsl:template>

<xsl:template match="lieferumfang">
    <lieferumfang aid:pstyle="lieferumfang"> <xsl:value-of select="." /></lieferumfang><xsl:text>&#xA;</xsl:text>
</xsl:template>

</xsl:stylesheet>

 
Damit InDesign die Attribute richtig verarbeitet, müssen wir in der XSL-Datei die zwei folgenden Zeilen voranstellen.

 xmlns:aid=“http://ns.adobe.com/AdobeInDesign/4.0/“
 xmlns:aid5=“http://ns.adobe.com/AdobeInDesign/5.0/“


<xsl:text>&#xA;</xsl:text> bewirkt einen harten Return.

Importiert bitte nun die XML-Datei neu in die InDesign-Datei tutorial_xml.indd mit folgenden Optionen: (Achtung: Soweit noch vorhanden, bitte alte XML-Daten aus dem Dokument löschen).

XSLT anwenden: erste.xsl.

Bilder



 
Das Ergebnis sollte jetzt wie folgt aussehen.

Bilder



Das Tag <Bekleidung> wurde in <root> umbenannt, das Tag <produkt> in <textfeld> dem die Elemente <li> und <lieferumfang> untergeordnet wurden.

Die Tags <li> und <Lieferumfang> haben zusätzlich jeweils ein Attribut aid:pstyle="" erhalten. Der Wert dieses Attributes legt das Absatzformat fest.

Es wurden zudem nur die Elemente importiert, die wir in unserer XSL-Datei berücksichtigt haben. Das Element <h1>, unsere Überschrift, fehlt.

 
Führt jetzt das Skript first.jsx aus dem 1. Teil aus und ihr seht, dass der Text nun formatiert wurde.

Bilder



Um eine Überschrift zu erhalten, erweitern wir unsere XSL-Datei.

Die Überschrift will ich in eine farbig hinterlegte Tabelle stecken. Das Tabellenformat ist schon in der InDesign-Datei angelegt. Tabelle_h1

erste.xsl

<?xml version="1.0" encoding="UTF-8"?>
 <xsl:stylesheet version="2.0"
 xmlns:aid="http://ns.adobe.com/AdobeInDesign/4.0/"
 xmlns:aid5="http://ns.adobe.com/AdobeInDesign/5.0/"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">



<xsl:attribute-set name="mytablestyle_h1">
        <xsl:attribute name="aid5:tablestyle">Tabelle_h1</xsl:attribute>
	<xsl:attribute name="aid:table">table</xsl:attribute>
	<xsl:attribute name="aid:trows"><xsl:value-of select="1"/></xsl:attribute>
	<xsl:attribute name="aid:tcols"><xsl:value-of select="1"/></xsl:attribute>
</xsl:attribute-set>

<xsl:template match="Bekleidung">
	<root>
  		<xsl:apply-templates select="produkt"/>
	</root>
</xsl:template>


<xsl:template match="produkt">
	
	<textfeld>
		<main>
	  		<xsl:apply-templates select="h1"/>
  			<xsl:apply-templates select="li"/>
  			<xsl:apply-templates select="lieferumfang"/>
		</main>
 	 </textfeld>
	
</xsl:template>

<xsl:template match="h1">
	<p aid:pstyle="p"><xsl:element name="Tabelle" use-attribute-sets="mytablestyle_h1">
	<cell aid:table="cell"  aid:crows="1" aid:ccols="1" aid:ccolwidth="348.660"> 
	<h1 aid:pstyle="h2"> <xsl:value-of select="." /></h1>
	</cell> 
	</xsl:element>
	</p><xsl:text>&#xA;</xsl:text>
</xsl:template>

<xsl:template match="li">
	<li aid:pstyle="li"><xsl:value-of select="." /></li><xsl:text>&#xA;</xsl:text>
</xsl:template>

<xsl:template match="lieferumfang">
	<lieferumfang aid:pstyle="lieferumfang"> <xsl:value-of select="." /></lieferumfang><xsl:text>&#xA;</xsl:text>
</xsl:template>

</xsl:stylesheet>

Als Erstes wird ein Attributset für die Tabelle_h1 festgelegt.

aid5:tablestyle“>Tabelle_h1 weist dem Element das Tabellenformat zu.

<xsl:attribute name=“aid:table“>table</xsl:attribute>
InDesign weiß nun, dass es sich um eine Tabelle handelt.

aid:trows“><xsl:value-of select=“1“/>
aid:tcols“><xsl:value-of select=“1“/>


 
Wir legen hiermit die Anzahl der Spalten und Zeilen fest; jeweils 1.

<xsl:element name=“Tabelle“ use-attribute-sets=““>
    <cell aid:table=“cell“  aid:crows=“1“ aid:ccols=“1“ aid:ccolwidth=“348.660“>
        <h1 aid:pstyle=“h2“> <xsl:value-of select=“.“ /</h1>
    </cell>
</xsl:element>


Hier wird nun ein Element mit dem Tag <Tabelle> generiert, welches unser oben genanntes Attributset mytablestyle_h1 verwenden soll. Dann wird die Zelle definiert; diese beinhaltet den Wert unserer Überschrift, dem ich leider das Absatzformat h2 zugeordnet habe, aber das lassen wir erst mal so.

ccolwidth=“348.660" Spaltenbreite

Aufgepasst: Wir haben noch ein <main> Element erstellt, welchem die Elemente <li>, <lieferumfang> und <h1>  direkt untergeordnet sind.

Öffnet nun die Original-Datei tutorial_xml.idml“, um sicherzugehen, dass keine Änderungen vorgenommen wurden oder sich nicht noch irgendwelche Restelemente aus vorherigen Schritten darin befinden.

Dann erste_daten.xml importieren und erste.xsl auswählen.

Startet wieder unser Skript first.jsx. Das Ergebnis:

Bilder



 
Bevor wir jetzt unsere XML-Datei erweitern und zur finalen XSL-Datei kommen, werden wir noch die Größe des Textfeldes automatisch anpassen lassen.

Hierzu gibt es 2 Wege (per Objektformat ab CS6 oder per Skript CS4/CS5):

Weg 1: Objektformat (bevorzugt, ab CS6)
Hierzu müssen wir in unserer InDesign-Datei ein neues Objektformat erstellen.

Erstellt hierzu ein neues Objektformat und nennt es txt_feld. Für unsere Zwecke reicht es erst mal, die automatische Größenänderung zu aktivieren.

Wählt die Option Nur Höhe sowie den Pfeil oben Mitte; Mindesthöhe 40 mm.

Bilder



Speichert die Datei sicherheitshalber ab.

Jetzt müssen wir noch unser Skript aus Teil 1 "second_step.jsx" um eine Zeile erweitern.

myTextFrame.appliedObjectStyle = myDocument.objectStyles.itemByName("txt_feld");

Dem Textfeld wird nun das Objektformat zugeordnet. Ihr könnt natürlich auch verschiedene Effekte und Hintergründe beim Objektformat testen.

second_step.jsx
var myDocument = app.documents.item(0);
var sitenumber = 1;
 
var inhalt= myDocument.xmlElements.item(0).xmlElements.item(0);
  
 set_textfeld(inhalt);
   
  function set_textfeld(inhalt){
    var myPage = myDocument.pages.item(sitenumber);
    var myTextFrame = myPage.textFrames.add();
    myTextFrame.appliedObjectStyle = myDocument.objectStyles.itemByName("txt_feld");
    myTextFrame.sendToBack();

    inhalt.placeXML(myTextFrame);
     
    myTextFrame.geometricBounds = myGetBounds();
    return
   }
 
function myGetBounds( ){
    myPage = myDocument.pages.item(sitenumber); 
    if(myPage.side == PageSideOptions.rightHand ){
          var myX1 = 227; var myX2 = 350;
    } else {
        var myX1 = 70; var myX2 = 193;
            }   
         
    var myY1 = 40;
    var myY2 = myY1+80;
    return [myY1, myX1, myY2, myX2];
}

 
Weg 2: nur Skript (ab CS4)
Alternativ können wir das Ganze komplett über eine zusätzliche Funktion lösen, ohne ein Objektformat anzuwenden.

Hierzu definieren wir die Höhe des Textfeldes auf 40 mm Höhe, und falls der Platz nicht reicht, wird das Textfeld vergrößert.

alternative_second_step.jsx
var myDocument = app.documents.item(0);
var sitenumber = 1;
var plusStep = 3;   
var minusStep = 0.5;  
var inhalt= myDocument.xmlElements.item(0).xmlElements.item(0);
 
 set_textfeld(inhalt);
  
  function set_textfeld(inhalt){
    var myPage = myDocument.pages.item(sitenumber);
    var myTextFrame = myPage.textFrames.add();
    myTextFrame.sendToBack();
    inhalt.placeXML(myTextFrame);
    myTextFrame.geometricBounds = myGetBounds();
  
    if (myTextFrame.overflows == true  ){
		setTfHeight(myTextFrame);
	}
    
    return 
   }

function myGetBounds( ){
    myPage = myDocument.pages.item(sitenumber);  
    if(myPage.side == PageSideOptions.rightHand ){
          var myX1 = 227; var myX2 = 350;
    } else {
        var myX1 = 70; var myX2 = 193; 
            }    
        
    var myY1 = 40;
    var myY2 = myY1+40;
    return [myY1, myX1, myY2, myX2];
}

function setTfHeight(_tf){   
	 	while(_tf.overflows == true){   
			var tfBounds = _tf.geometricBounds;   
                        
                _tf.geometricBounds = [tfBounds[0], tfBounds[1], tfBounds[2] + plusStep, tfBounds[3]];   
                }   
            setHeightByBaseline(_tf);  
        }   
    
function setHeightByBaseline(_tf01)  {   
         var tmpArray = [];   
        for(var tc = 0; tc < _tf01.textColumns.length; tc++)   
        {   
            myColumn = _tf01.textColumns[tc];   
            tmpArray.push(myColumn.lines[-1].baseline);
            }   
         tmpArray.sort(Numsort);   
        var actualTfBounds = _tf01.geometricBounds;   
        _tf01.geometricBounds = [actualTfBounds[0], actualTfBounds[1], tmpArray[tmpArray.length -1], actualTfBounds[3]]; 
        }
        function Numsort (a, b) {   
        return a - b;   
} 

Mit myTextframe.overlows überprüfen wir, ob ein Overlow/Übersatztext besteht. Falls ja, wird eine Funktion aufgerufen, welche das Textobjekt schrittweise vergrößert (diese Funktion habe ich von hier: http://www.hilfdirselbst.ch/foren/InDesign_mehrspaltige_Textrahmen_an_Inhalt_anpassen_P499638.html.

Zum Schluss möchte ich euch nun eine kleine Vorschau geben, mit welcher XML-Datei wir im dritten Teil weiterarbeiten werden, sowie eine kurze Erklärung zur erweiterten XSL-Datei.

Wir bleiben im Bereich Bekleidung. Wichtig ist, dass alle Elemente, die zusammengehören, einem Parent Tag untergeordnet sind. Ansonsten bekommen wir später in InDesign große Probleme.

Als Beispiel haben wir Hauptprodukte wie z.B. ein T-Shirt, eine Hose, einen Pulli, die es in verschiedenen Größen und Materialien gibt.

zweite_daten.xml  (Ausschnitt / siehe Arbeitsdaten)
....	
	<produkt>
		<h1>T-shirt Laola</h1>
		<bild>mm.jpg</bild>
		<li>Leicht zu tragen</li>
		<li>Färbt nicht ab</li>
		<li>Fair Trade</li>
		<lieferumfang>T-Shirt</lieferumfang>
		<artikel nummer="1">
			<groesse>s</groesse>
			<Preis>21</Preis>
			<material>gumi</material>
		</artikel>
		<artikel nummer="2">
			<Groesse>m</Groesse>
			<Preis>23</Preis>
			<material>Baumwolle</material>
		</artikel>
		<artikel nummer="3">
			<Groesse>l</Groesse>
			<Preis>243</Preis>
			<material>Papier</material>
		</artikel>
		<artikel nummer="4">
			<Groesse>XL</Groesse>
			<Preis>253</Preis>
			<material>Polyester</material>
		</artikel>
		<hinweis>
			<Rabatt>
				<li>20%</li>
			</Rabatt>
			<Sonstiges>
				<li>dies</li>
				<li>dies</li>
			</Sonstiges>
		</hinweis>
	</produkt>
	<produkt> ...
	......
	......
Das erste Produkt ist ein "T-Shirt Laola" mit einer Bild-Datei und bestimmten Vorteilen/Merkmalen, die für jede Größe gelten. Dieses Produkt gibt es in verschiedenen Größen und zu unterschiedlichen Preisen, deshalb gibt es eine Vielzahl von Artikeln mit jeweils einer eindeutigen Nummer (ID).

Unser Katalog soll entsprechend aussehen.

Überschrift -> Bild-> Liste mit Vorteilen-> Lieferumfang-> Tabelle mit Größen / Material / Artikelnummern ... Sonstiges.

Um später eine saubere Formatierung zu haben, müssen wir während des Imports der XML-Datei eine XSL-Transformation durchführen. Hierzu erweitern wir uns unsere XSL-Datei.

Diese findet ihr ebenfalls in den Arbeitsdateien. zweite.xsl

Wenn ihr diese Datei mit dem Editor öffnet, seht ihr, dass einige Zeilen Code zusammengekommen sind. Der Hauptteil ist nötig für eine dynamische Tabellen-Berechnung. Bei unserer XML-Datei gehe ich davon aus, dass die Spaltenanzahl, Zeilenlänge und Inhaltslänge variieren können.

<xsl:attribute-set name="mytablestyle">

<xsl:attribute name="aid:trows"><xsl:value-of select="count(artikel)+1"/></xsl:attribute>

Anzahl der Zeilen = Anzahl Elemente <artikel> + 1 x Kopfzeile  

<xsl:attribute name="aid:tcols"><xsl:value-of select="count(artikel[1]/*)+1"/></xsl:attribute>

Anzahl Spalten = Anzahl Kindelemente von <artikel> + 1 x Spalte Artikelnummer

<xsl:call-template name="table_th_not_def">

Hier wird dann mithilfe 3er Schleifen die Spaltenbreite berechnet. Die Anzahl der Strings in einer Spalte werden miteinander verglichen, der höchste Wert wird dann um einen gewissen Faktor multipliziert. Die so erhaltene Spaltenbreite wird dann von der Gesamttabellenbreite abgezogen.

Dies wird nun für jede Spalte so gemacht. Die letzte Spalte Artikelnummer nehme ich als Ausgleich.
Nicht ganz optimal, aber für unsere Zwecke erst mal ausreichend.

Sucht bitte in der Datei zweite.xsl fast am Ende folgende Zeile:

<xsl:attribute name="href">file:///f:/bilder/<xsl:value-of select="." /></xsl:attribute>

Achtung: Ihr müsst den Pfad für die Bilddatei file:///f:/bilder/ bei euch entsprechend anpassen!

Löscht nun alle vorhandenen XML-Daten aus eurer tutorial_xml.indd sowie vorhandene Textfelder auf der zweiten Seite (ausgenommen Felder auf der Musterseite).

Importiert dann die zweite_daten.xml und verwendet beim Import die zweite.xsl.

Startet das Skript second_step.jsx.

 
Das Ergebnis sollte nun folgendermaßen aussehen:

Bilder



Die Darstellung der Bilddatei kann variieren.

Im dritten Teil werden wir eine Schleife schreiben, um für alle XML-Elemente ein Textfeld zu erstellen, das Bild anzupassen und die zweite Tabelle in ein eigenes Textfeld zu platzieren.




Kommentare
Achtung: Du kannst den Inhalt erst nach dem Login kommentieren.
Portrait von Indesbeginner
  • 29.07.2017 - 20:15

Auch dieser Teil ist Top! :-)
Ich bin schon gespannt auf Teil 3.

Portrait von moschi
  • 30.08.2014 - 18:19

Vielen Dank, freue mich auf mehr!

Portrait von der_fou
  • 30.08.2014 - 14:06

Vielen Dank fürs tutorial! Ich freu mich schon auf den nächsten Teil!!

Portrait von johanna52
  • 30.08.2014 - 13:45

tolles, sehr gut erklärtes und interessantes Tutorial

Portrait von Caesarion2004
  • 30.08.2014 - 13:37

Vielen Dank für das interessante und hiflreiche Tutorial in Textform.

Portrait von BOPsWelt
  • 30.08.2014 - 13:33

Danke für das Tutorial.

x
×
×