XML-import MySQL - Casus lente 2018

Uit De Vliegende Brigade
Versie door Jeroen Strompf (overleg | bijdragen) op 13 nov 2018 om 18:13
(wijz) ← Oudere versie | Huidige versie (wijz) | Nieuwere versie → (wijz)
Naar navigatie springen Naar zoeken springen

M'n eerste grote MySQL-XML-import! Dit was de aanleiding voor mij om XSL te leren. Dit betrof Exact productgegevens.

Voorbeeld-data

<?xml version="1.0"?>
<Items>

   <Item code="00000001" type="S">
      <Description>Dinges_01</Description>
      <FreeFields>
           <FreeTexts>
            <FreeText number="1"/>
            <FreeText number="2">Veld_02</FreeText>
            <FreeText number="3">Veld_03</FreeText>
            <FreeText number="4"/>
         </FreeTexts>
      </FreeFields>

      <ItemCategory number="9" code="">
           <Description/>
      </ItemCategory>

      <ItemCategory number="10" code="2">
           <Description>Bezig</Description>
      </ItemCategory>

   </Item>



   <Item code="00000002" type="S">

      <Description>Widget_01</Description>
      <FreeFields>
           <FreeTexts>
            <FreeText number="1"/>
            <FreeText number="2">Field_02</FreeText>
            <FreeText number="3">Field_03</FreeText>
            <FreeText number="4"/>
         </FreeTexts>
      </FreeFields>

      <ItemCategory number="9" code="">
           <Description/>
      </ItemCategory>

      <ItemCategory number="10" code="2">
           <Description>Active</Description>
      </ItemCategory>

   </Item>

</Items>

Het probleem

Import van bovenstaande voorbeelddata brengt een paar problemen met zich mee:

  • Niet-lineair: Dit XML-bestand kun je niet 1-op-1 kunt importeren in een tabel omdat er subelementen zijn. Gelukkig zijn er geen subelementen met een variabel aantal elementen - Dat zou overeenkomen met tabellen met een één-op-veel-relatie
  • Ambivalente tagnamen: Het veld Description komt op twee plekken voor, maar is niet hetzelfde
  • Attributen:Een database weet geen raad met attributen. In het bijzonder:
    • Attributen → Tagnaam: Attributen die onderdeel zouden moeten zijn van de tagnaam (bv. freetext_1)
    • Attributen → Subnode: Attributen die een subnode zouden moeten zijn (bv. item » code)
  • Parent-nodes: Databases kunnen niet overweg met parent-nodes (bv. Items en Freefields)
  • Naamgevingsconventie: Graag handigere naamgeving: Ik gebruik in MySQL underscores ipv. hoofdletters.

Aanpak

Alle bestanden. Het is iteratief, muv. het 'hoofdprogramma': Daar is maar één instantie van

Dit vereist een handjevol transformaties. Die heb ik ondergebracht in verschillende bestanden.

Hoofdprogramma

Het 'hoofdprogramma', 100.py, is geschreven in Python:

#!/usr/bin/python


################################################################
# Import
################################################################
#
import os
import lxml.etree as ET


################################################################
# Attributen 2 elements
################################################################
#
source_xml_file_name=	"112 - Bron - 2000 regels.xml" # 111 - Bron - 26 regels (lastiger).xml"
xsl_file_name=		"120 - attributes2elementes.xsl"
output_xml_file_name=	"130 - Output - attributen gefixet.xml"

transform = ET.XSLT(ET.parse(xsl_file_name))
newdom = transform(ET.parse(source_xml_file_name))
xmlfile = open(os.path.join('',output_xml_file_name),'wb')
xmlfile.write(newdom)
xmlfile.close()


################################################################
# Make tags unique
################################################################
#
source_xml_file_name=	"130 - Output - attributen gefixet.xml"
xsl_file_name=		"140 - Make tags unique.xsl"
output_xml_file_name=	"150 - Output.xml"

transform = ET.XSLT(ET.parse(xsl_file_name))
newdom = transform(ET.parse(source_xml_file_name))
xmlfile = open(os.path.join('',output_xml_file_name),'wb')
xmlfile.write(newdom)
xmlfile.close()


################################################################
# Attributes 2 field names
################################################################
#
source_xml_file_name=	"150 - Output.xml"
xsl_file_name=		"160 - Transform attributes to field names.xsl"
output_xml_file_name=	"170 - Output.xml"

transform = ET.XSLT(ET.parse(xsl_file_name))
newdom = transform(ET.parse(source_xml_file_name))
xmlfile = open(os.path.join('',output_xml_file_name),'wb')
xmlfile.write(newdom)
xmlfile.close()


################################################################
# Make fieldnames unique (2)
################################################################
#
source_xml_file_name=	"170 - Output.xml"
xsl_file_name=		"175 - make tags unique (2).xsl"
output_xml_file_name=	"178 - Output.xml"

transform = ET.XSLT(ET.parse(xsl_file_name))
newdom = transform(ET.parse(source_xml_file_name))
xmlfile = open(os.path.join('',output_xml_file_name),'wb')
xmlfile.write(newdom)
xmlfile.close()


################################################################
# Remove parents
################################################################
#
source_xml_file_name=	"178 - Output.xml"
xsl_file_name=		"180 - Remove parents.xsl"
output_xml_file_name=	"190 - Output.xml"

transform = ET.XSLT(ET.parse(xsl_file_name))
newdom = transform(ET.parse(source_xml_file_name))
xmlfile = open(os.path.join('',output_xml_file_name),'wb')
xmlfile.write(newdom)
xmlfile.close()


################################################################
# Fix names
################################################################
#
source_xml_file_name=	"190 - Output.xml"
xsl_file_name=		"200 - Fix names.xsl"
output_xml_file_name=	"210 - Output.xml"

transform = ET.XSLT(ET.parse(xsl_file_name))
newdom = transform(ET.parse(source_xml_file_name))
xmlfile = open(os.path.join('',output_xml_file_name),'wb')
xmlfile.write(newdom)
xmlfile.close()


################################################################
# Finishing touches
################################################################
#
source_xml_file_name=	"210 - Output.xml"
xsl_file_name=		"900 - Finishing touches.xsl"
output_xml_file_name=	"950 - Output - Final.xml"

transform = ET.XSLT(ET.parse(xsl_file_name))
newdom = transform(ET.parse(source_xml_file_name))
xmlfile = open(os.path.join('',output_xml_file_name),'wb')
xmlfile.write(newdom)
xmlfile.close()

Verschillende datasets

Bestanden

  • 110 - Bron - 26 regels.xml
  • 111 - Bron - 26 regels (lastiger).xml
  • 112 - Bron - 2000 regels.xml
  • 114 - Bron - Alles.xml

zijn verschillende datasets. 'Alles' is 22,5 MB groot en tegen een miljoen regels. Het duurt ca. twee minuten om dat bestand te parsen, en da's tijdens testen zonde van de tijd. Het werkte prima om op deze manier een verschillend aantal datasets te hebben. Vaak raak ik de weg kwijt als er verschillende testdata is, maar nu niet.

120 - attributes2elementes.xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!-- ======================= -->
<!-- Identity Transformation -->
<!-- ======================= -->

<xsl:template match="node()">
   <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
</xsl:template>


<!-- =========================================== -->
<!-- Alle attributen omfietsen naar subelementen -->
<!-- =========================================== -->

   <xsl:template match="@*">
      <xsl:element name="{name(..)}_{name()}">
         <xsl:value-of select="." />
      </xsl:element>
   </xsl:template>
</xsl:stylesheet>

140 - Make tags unique.xsl

<!-- =========================================== -->
<!-- Maak velden uniek, maar alleen als daardoor -->
<!-- geen attributen verloren gaan               -->
<!-- =========================================== -->

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


<!-- Identity transformation -->

<xsl:template match="@*|node()">
   <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
</xsl:template>


<!-- Item/Description -->

<xsl:template match="Item/Description">
   <item_description>
      <xsl:apply-templates/>
   </item_description>
</xsl:template>


<!-- Assortment/Description -->

<xsl:template match="Assortment/Description">
   <assortment_description>
      <xsl:apply-templates/>
   </assortment_description>
</xsl:template>


<!-- Availability/DateStart -->

<xsl:template match="Availability/DateStart">
   <availability_date_start>
      <xsl:apply-templates/>
   </availability_date_start>
</xsl:template>


<!-- Availability/DateEnd -->

<xsl:template match="Availability/DateEnd">
   <availability_date_end>
      <xsl:apply-templates/>
   </availability_date_end>
</xsl:template>


<!-- Sales/Price -->

<xsl:template match="Sales/Price">
   <sales_price>
      <xsl:apply-templates/>
   </sales_price>
</xsl:template>


<!-- Sales//Price_type -->

<xsl:template match="Sales//Price_type">
   <sales_price_type>
      <xsl:apply-templates/>
   </sales_price_type>
</xsl:template>


<!-- Sales//Value -->

<xsl:template match="Sales//Value">
   <sales_value>
      <xsl:apply-templates/>
   </sales_value>
</xsl:template>


<!-- Sales//Currency_code -->

<xsl:template match="Sales//Currency_code">
   <sales_currency_code>
      <xsl:apply-templates/>
   </sales_currency_code>
</xsl:template>


<!-- Sales//VAT_code -->

<xsl:template match="Sales//VAT_code">
   <sales_vat_code>
      <xsl:apply-templates/>
   </sales_vat_code>
</xsl:template>


<!-- Costs//Currency_code -->

<xsl:template match="Costs//Currency_code">
   <costs_currency_code>
      <xsl:apply-templates/>
   </costs_currency_code>
</xsl:template>


<!-- Costs//Values -->

<xsl:template match="Costs//Value">
   <costs_value>
      <xsl:apply-templates/>
   </costs_value>
</xsl:template>

</xsl:stylesheet>

160 - Transform attributes to field names.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="yes" />

<!-- Transfer former attributes to tag names     -->
<!-- =========================================== -->
<!--                                             -->
<!-- For selected fields only                    -->


<!-- =========================================== -->
<!-- Identity Transformation                     -->
<!-- =========================================== -->
<!--                                             -->
<xsl:template match="@*|node()">
   <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
</xsl:template>


<!-- =========================================== -->
<!-- FreeText                                    -->
<!-- =========================================== -->
<!--                                             -->
<xsl:template match="FreeText">
    <xsl:variable name="veld_nummer" select="FreeText_number" />
    <xsl:element name="free_text_{$veld_nummer}">
    <xsl:value-of select="./text()"/>
  </xsl:element>
</xsl:template>


<!-- =========================================== -->
<!-- FreeDate                                -->
<!-- =========================================== -->

<xsl:template match="FreeDate">
  	<xsl:variable name="veld_nummer" select="FreeDate_number" />
  	<xsl:element name="free_date_{$veld_nummer}">
		  <xsl:value-of select="./text()"/>
  </xsl:element>
</xsl:template>


<!-- =========================================== -->
<!-- FreeNumber                                -->
<!-- =========================================== -->

<xsl:template match="FreeNumber">
    <xsl:variable name="veld_nummer" select="FreeNumber_number" />
    <xsl:element name="free_number_{$veld_nummer}">
      <xsl:value-of select="./text()"/>
  </xsl:element>
</xsl:template>


<!-- =========================================== -->
<!-- ItemCategory                            -->
<!-- =========================================== -->

<!-- Scope: Alleen ItemCategory-nodes -->

<xsl:template match="ItemCategory">

    <!-- Kopieer waarde van 'number' naar variable -->

    <xsl:variable name="veld_nummer" select="ItemCategory_number" />

    <!-- Creer item_category_number_x_code - veld -->

    <xsl:element name="item_category_{$veld_nummer}">
      <xsl:apply-templates select="ItemCategory_code"/>
      <xsl:apply-templates select="Description"/>
    </xsl:element>


</xsl:template>


<!-- =========================================== -->
<!-- FreeYesNo                            -->
<!-- =========================================== -->

<xsl:template match="FreeYesNo">
    <xsl:variable name="veld_nummer" select="FreeYesNo_number" />
    <xsl:element name="free_yes_no_{$veld_nummer}">
      <xsl:value-of select="./text()"/>
  </xsl:element>
</xsl:template>

</xsl:stylesheet>

175 - make tags unique (2).xsl

<!-- =========================================== -->
<!-- Maak velden uniek, maar alleen als daardoor -->
<!-- geen attributen verloren gaan               -->
<!-- =========================================== -->

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*" />
<xsl:output indent="yes"/>



<!-- =========================================== -->
<!-- Identity transformation -->
<!-- =========================================== -->

<xsl:template match="@*|node()">
   <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
</xsl:template>


<!-- =========================================== -->
<!-- item_category - ItemCategory_code           -->
<!-- =========================================== -->

<xsl:template match="item_category_1//ItemCategory_code">
   <item_category_1_code>
      <xsl:apply-templates/>
   </item_category_1_code>
</xsl:template>

<xsl:template match="item_category_2//ItemCategory_code">
   <item_category_2_code>
      <xsl:apply-templates/>
   </item_category_2_code>
</xsl:template>

<xsl:template match="item_category_3//ItemCategory_code">
   <item_category_3_code>
      <xsl:apply-templates/>
   </item_category_3_code>
</xsl:template>

<xsl:template match="item_category_4//ItemCategory_code">
   <item_category_4_code>
      <xsl:apply-templates/>
   </item_category_4_code>
</xsl:template>

<xsl:template match="item_category_5//ItemCategory_code">
   <item_category_5_code>
      <xsl:apply-templates/>
   </item_category_5_code>
</xsl:template>

<xsl:template match="item_category_6//ItemCategory_code">
   <item_category_6_code>
      <xsl:apply-templates/>
   </item_category_6_code>
</xsl:template>

<xsl:template match="item_category_7//ItemCategory_code">
   <item_category_7_code>
      <xsl:apply-templates/>
   </item_category_7_code>
</xsl:template>

<xsl:template match="item_category_8//ItemCategory_code">
   <item_category_8_code>
      <xsl:apply-templates/>
   </item_category_8_code>
</xsl:template>

<xsl:template match="item_category_9//ItemCategory_code">
   <item_category_9_code>
      <xsl:apply-templates/>
   </item_category_9_code>
</xsl:template>

<xsl:template match="item_category_10//ItemCategory_code">
   <item_category_10_code>
      <xsl:apply-templates/>
   </item_category_10_code>
</xsl:template>


<!-- =========================================== -->
<!-- item_category - Description                 -->
<!-- =========================================== -->

<xsl:template match="item_category_1//Description">
   <item_category_1_description>
      <xsl:apply-templates/>
   </item_category_1_description>
</xsl:template>

<xsl:template match="item_category_2//Description">
   <item_category_2_description>
      <xsl:apply-templates/>
   </item_category_2_description>
</xsl:template>

<xsl:template match="item_category_3//Description">
   <item_category_3_description>
      <xsl:apply-templates/>
   </item_category_3_description>
</xsl:template>

<xsl:template match="item_category_4//Description">
   <item_category_4_description>
      <xsl:apply-templates/>
   </item_category_4_description>
</xsl:template>

<xsl:template match="item_category_5//Description">
   <item_category_5_description>
      <xsl:apply-templates/>
   </item_category_5_description>
</xsl:template>

<xsl:template match="item_category_6//Description">
   <item_category_6_description>
      <xsl:apply-templates/>
   </item_category_6_description>
</xsl:template>

<xsl:template match="item_category_7//Description">
   <item_category_7_description>
      <xsl:apply-templates/>
   </item_category_7_description>
</xsl:template>

<xsl:template match="item_category_8//Description">
   <item_category_8_description>
      <xsl:apply-templates/>
   </item_category_8_description>
</xsl:template>

<xsl:template match="item_category_9//Description">
   <item_category_9_description>
      <xsl:apply-templates/>
   </item_category_9_description>
</xsl:template>

<xsl:template match="item_category_10//Description">
   <item_category_10_description>
      <xsl:apply-templates/>
   </item_category_10_description>
</xsl:template>

</xsl:stylesheet>

180 - Remove parents.xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*" />
<xsl:output indent="yes"/>

<!--
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes" encoding="UTF-8" />
<xsl:strip-space elements="*" />

-->

<!-- =========================================== -->
<!-- Identity Transformation                     -->
<!-- =========================================== -->
<!--                                             -->
<xsl:template match="@*|node()">
   <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
</xsl:template>


<!-- =========================================== -->
<!-- Remove parents - alphabetically             -->
<!-- =========================================== -->


<xsl:template match="Assortment">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="Availability">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="Costs">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="Currency">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="FreeDates">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="FreeFields">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="FreeNumbers">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="FreeTexts">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="FreeYesNos">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="ItemCategory">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="item_category_1"><xsl:apply-templates select="*"/></xsl:template>
<xsl:template match="item_category_2"><xsl:apply-templates select="*"/></xsl:template>
<xsl:template match="item_category_3"><xsl:apply-templates select="*"/></xsl:template>
<xsl:template match="item_category_4"><xsl:apply-templates select="*"/></xsl:template>
<xsl:template match="item_category_5"><xsl:apply-templates select="*"/></xsl:template>
<xsl:template match="item_category_6"><xsl:apply-templates select="*"/></xsl:template>
<xsl:template match="item_category_7"><xsl:apply-templates select="*"/></xsl:template>
<xsl:template match="item_category_8"><xsl:apply-templates select="*"/></xsl:template>
<xsl:template match="item_category_9"><xsl:apply-templates select="*"/></xsl:template>
<xsl:template match="item_category_10"><xsl:apply-templates select="*"/></xsl:template>


<xsl:template match="Price">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="Sales">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="sales_price">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="Unit">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="VAT">
  <xsl:apply-templates select="*"/>
</xsl:template>

</xsl:stylesheet>

200 - Fix names.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" encoding="UTF-8" />
<xsl:strip-space elements="@*|node()" />


<!-- =========================================== -->
<!-- Identity Transformation                     -->
<!-- =========================================== -->
<!--                                             -->
<xsl:template match="@*|node()">
   <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
</xsl:template>


<!-- =========================================== -->
<!-- Fix names -->
<!-- =========================================== -->

<xsl:template match="Item">                    <item>                       <xsl:apply-templates select="@*|node()"/>   </item>                       </xsl:template>
<xsl:template match="Item_code">               <item_code>                  <xsl:apply-templates select="@*|node()"/>   </item_code>                  </xsl:template>
<xsl:template match="Item_type">               <item_type>                  <xsl:apply-templates select="@*|node()"/>   </item_type>                  </xsl:template>
<xsl:template match="Assortment_number">       <assortment_number>          <xsl:apply-templates select="@*|node()"/>   </assortment_number>          </xsl:template>
<xsl:template match="Assortment_code">         <assortment_code>            <xsl:apply-templates select="@*|node()"/>   </assortment_code>            </xsl:template>
<xsl:template match="Condition">               <condition_field>            <xsl:apply-templates select="@*|node()"/>   </condition_field>            </xsl:template>
<xsl:template match="IsSalesItem">             <is_sales_item>              <xsl:apply-templates select="@*|node()"/>   </is_sales_item>              </xsl:template>
<xsl:template match="IsPurchaseItem">          <is_purchase_item>           <xsl:apply-templates select="@*|node()"/>   </is_purchase_item>           </xsl:template>
<xsl:template match="IsStockItem">             <is_stock_item>              <xsl:apply-templates select="@*|node()"/>   </is_stock_item>              </xsl:template>
<xsl:template match="IsFractionAllowedItem">   <is_fraction_allowed_item>   <xsl:apply-templates select="@*|node()"/>   </is_fraction_allowed_item>   </xsl:template>
<xsl:template match="IsTextItem">              <is_text_item>               <xsl:apply-templates select="@*|node()"/>   </is_text_item>               </xsl:template>
<xsl:template match="IsDiscountItem">          <is_discount_item>           <xsl:apply-templates select="@*|node()"/>   </is_discount_item>           </xsl:template>
<xsl:template match="IsPrintItem">             <is_print_item>              <xsl:apply-templates select="@*|node()"/>   </is_print_item>              </xsl:template>
<xsl:template match="Unit_active">             <unit_active>                <xsl:apply-templates select="@*|node()"/>   </unit_active>                </xsl:template>
<xsl:template match="Unit_unit">               <unit_unit>                  <xsl:apply-templates select="@*|node()"/>   </unit_unit>                  </xsl:template>
<xsl:template match="Unit_type">               <unit_type>                  <xsl:apply-templates select="@*|node()"/>   </unit_type>                  </xsl:template>

<!--
	Dit geeft een foutmelding!
	Heeft dit met de volgorde te maken?

	<xsl:template match="Unit_active>"> 			<unit_active> 				<xsl:apply-templates select="@*|node()"/> 	</unit_active> 					</xsl:template>

-->

</xsl:stylesheet>

900 - Finishing touches.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />

<!--
	Last transformations before importing in db
	===========================================

	After this, the file isn't a well-formed 
	XML file anymore

-->	


<!-- =========================================== -->
<!-- Identity Transformation                     -->
<!-- =========================================== -->
<!--                                             -->
<xsl:template match="@*|node()">
   <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
</xsl:template>

<!-- =========================================== -->
<!-- Remove parent                               -->
<!-- =========================================== -->
<!--                                             -->

  <xsl:template match="Items">
    <xsl:apply-templates select="*"/>
  </xsl:template>



</xsl:stylesheet>

Eindresultaat

<item>
  <item_code>00000001</item_code>
  <item_type>S</item_type>
  <item_description>Dinges_01</item_description>
  <free_text_1/>
  <free_text_2>Veld_02</free_text_2>
  <free_text_3>Veld_03</free_text_3>
  <free_text_4/>
  <item_category_9_code/>
  <item_category_9_description/>
  <item_category_10_code>2</item_category_10_code>
  <item_category_10_description>Bezig</item_category_10_description>
</item>

<item>
  <item_code>00000002</item_code>
  <item_type>S</item_type>
  <item_description>Widget_01</item_description>
  <free_text_1/>
  <free_text_2>Field_02</free_text_2>
  <free_text_3>Field_03</free_text_3>
  <free_text_4/>
  <item_category_9_code/>
  <item_category_9_description/>
  <item_category_10_code>2</item_category_10_code>
  <item_category_10_description>Active</item_category_10_description>
</item>

Overig

  • Ongetwijfeld kan deze code veel eenvoudiger
  • Ik werd tureluurs van het werken met zoveel bestanden: eindeloos wisselen van context. Ik had de indruk dat er niet een voor-de-hand-liggende manier is, om XSL-bestanden samen te voegen. Wat uiteindelijk heel aardig werkte: Bestanden steeds sluiten na gebruik, en opnieuw openen als ik ze weer nodig heb. Blijkbaar is het voor mij gemakkelijker om bestanden in Nautilus te selecteren, dan uit geopende vensters. Wat dat laatste betreft: Met ALT-TAB kan ik welliswaar wisselen tussen geopende instanties van Sublime, maar de titel van de bestanden kan ik dan niet zien
  • In een vrij laat stadium kwam ik erachter dat ItemCategory anders in elkaar zat dan de overige structuren. Vandaar bestand 175 - make tags unique (2).xsl.

Design patterns

Mijn evaring tot op heden:

  • Elke stylesheet z'n eigen functie: Zorg ervoor dat de functie van elk stylesheet-bestand (gewoon elk xsl-bestand) duidelijk is: Dat helpt bij debuggen, omdat ik anders niet meer weet waar ik een bepaalde transformatie moet zoeken. Soms is samenvoegen heel duidelijk (bv. tags uniek maken + namen aanpassen in een ander project). Als dit niet glashelder is: Niet samenvoegen!
  • Geen parent-namen aanpassen als die parents toch verdwijnen: Ligt voor de hand, maar het is oh zo aantrekkelijk om dat toch anders te doen
  • Complete padnamen & controle van de fout: Vaak overkill om ItemPrice/Discounts/Discount/Discount_number als match te gebruiken, als Discount_number ook werkt. En toch is de eerste variant soms handig: Ter controle van de fout: De match is heel specifiek, en als ik toch een andere match over het hoofd zie, komt dit tenminste aan de orde. Wel zo handig bij bestanden die te groot zijn om handmatig te inventariseren.

Volgorde van transformaties

  1. Rare header verwijderen (bv. een regel met eExact waar XSL zich in verslikt - Handmatig, maar da's nu geen probleem)
  2. Speciale gevallen, bv. attribuutnamen of -waardes die toegepast moeten worden op meerdere subnodes
  3. Attribuutnamen → subelementen
  4. Tagnames - Maak uniek + naming convention + Vermijd conflicterende MySQL-keywords
  5. Attributen → Veldnamen
  6. Parenteel verwijderen
  7. Finishing touches.

Bestandorganisatie

  • Nummer de bestanden - Dat helpt. Net als een BASIC-programma uit de jaren '80
  • Spaties & hoofdletters geen probleem
  • Extra ruimte ter plekke voor Python-bestanden. Die tellen namelijk niet iteratief mee, maar blijven aan het begin staan (bv. 100.py, 110.py, 120 - Alleen debuggen.py)
  • Extra ruimte ter plekke voor bron-bestanden. Deze 'lopen' ook niet iteratief mee, maar staan aan het begin. Bv. 200 - test (10 regels).xml, 210 - Test (5.000 regels).xml, 220 - Tutti.xml
  • Begin het eerste stylesheet niet 'aan het begin': Goede kans dat ik later nog een bestand moet invoegen. Daarom beginnen met bv. 350 - Attributes2tags.xsl en niet 300 - Attributes2tags.xsl.

Zie ook

De meeste XSL-code wordt elders al behandeld: