I have the following problem that, for me, is kind of tricky,
Basically I need to be able to modify a XML input file with data that I have stored in another XML file, so I would have to use 2 input XML files,
I have the following XML file, which is the one I want to modify (basically, just make additions to it):
<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.23" id="1">
<text-prop name="displayName">PersonTemplate</text-prop>
<setup>
<simple-master-page name="MasterPage" id="2">
<footer>
<text id="3">
<prop name="contentType">html</prop>
<text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-prop>
</text>
</footer>
</simple-master-page>
</setup>
<body>
<table id="4">
<column id="17"/>
<column id="18"/>
<column id="19"/>
<header>
<row id="5">
<cell id="6">
<label id="20">
<text-prop name="text">NameTitle</text-prop>
</label>
</cell>
<cell id="7">
<label id="21">
<text-prop name="text">CityTitle</text-prop>
</label>
</cell>
<cell id="8">
<label id="22">
<text-prop name="text">AgeTitle</text-prop>
</label>
</cell>
</row>
</header>
<detail>
<row id="9">
<cell id="10"/>
<cell id="11"/>
<cell id="12"/>
</row>
</detail>
</table>
</body>
</report>
And I want to make modify/make additions to it by consulting another XML file, this one, that gives me the data I want to put in the first XML file:
<?xml version="1.0" encoding="utf-8"?>
<model>
<layouts>
<layout ID="001" name="PersonTemplate" format="Table" nFields="3" >
<fields>
<field name="NameTitle"/>
<field name="CityTitle"/>
<field name="AgeTitle"/>
</fields>
</layout>
<layout ID="002" name="SchoolTemplate" format="Table" nFields="3" >
<fields>
<field name="NameTitle"/>
<field name="LocationTitle"/>
<field name="MaxCapacityTitle"/>
</fields>
</layout>
</layouts>
<reports>
<report layoutID="001">
<params>
<sources>
<source name="source1" dbURL="sampledb1.com" user="user1" password="dXNlcjE=" driver="dbDriver"/>
<source name="source2" dbURL="sampledb2.com" user="user2" password="dXNlcjI=" driver="dbDriver"/>
</sources>
<set name="set1" source="source1" querie="select Name, City, Age from PeopleTable" >
<qFields>
<qField name="Name" type="string"/>
<qField name="City" type="string"/>
<qField name="Age" type="integer"/>
</qFields>
</set>
</params>
</report>
<report layoutID="002">
<params>
<sources>
<source name="source1" dbURL="sampledb1.com" user="user1" password="dXNlcjE=" driver="dbDriver"/>
</sources>
<set name="Data Set" dataSource="source1" querie="select Name, Location, MaxCapacity from SchoolsTable" >
<qFields>
<qField name="Name" type="string"/>
<qField name="Location" type="string"/>
<qField name="MaxCapacity" type="integer"/>
</qFields>
</set>
</params>
</report>
</reports>
</model>
So, I want to produce the following XML file:
<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.23" id="1">
<text-prop name="displayName">PersonTemplate</text-prop>
<data-sources>
<data-source extensionID="this.is.a.fixed.value" name="source1">
<prop name="DriverClass">dbDriver</prop>
<prop name="databaseURL">sampledb1.com</prop>
<prop name="dbUser">user1</prop>
<encrypted-prop name="dbPassword" encryptionID="base64">dXNlcjE=</encrypted-prop>
</data-source>
</data-sources>
<data-sets>
<data-set extensionID="this.is.a.fixed.value" name="set1">
<list-prop name="columnHints">
<struct>
<prop name="columnName">Name</prop>
<text-prop name="displayName">Name</text-prop>
<text-prop name="heading">Name</text-prop>
</struct>
<struct>
<prop name="columnName">City</prop>
<text-prop name="displayName">City</text-prop>
<text-prop name="heading">City</text-prop>
</struct>
<struct>
<prop name="columnName">Age</prop>
<text-prop name="displayName">Age</text-prop>
<text-prop name="heading">Age</text-prop>
</struct>
</list-prop>
<struct name="cachedMetaData">
<list-prop name="resultSet">
<struct>
<prop name="position">1</prop>
<prop name="name">Name</prop>
<prop name="dataType">string</prop>
</struct>
<struct>
<prop name="position">2</prop>
<prop name="name">City</prop>
<prop name="dataType">string</prop>
</struct>
<struct>
<prop name="position">3</prop>
<prop name="name">Age</prop>
<prop name="dataType">integer</prop>
</struct>
</list-prop>
</struct>
<prop name="dataSource">source1</prop>
<list-prop name="resultSet">
<struct>
<prop name="position">1</prop>
<prop name="name">Name</prop>
<prop name="dataType">string</prop>
</struct>
<struct>
<prop name="position">2</prop>
<prop name="name">City</prop>
<prop name="dataType">string</prop>
</struct>
<struct>
<prop name="position">3</prop>
<prop name="name">AGE</prop>
<prop name="dataType">integer</prop>
</struct>
</list-prop>
<xml-prop name="queryText"><![CDATA[select Name, City, Age from PeopleTable]]></xml-prop>
</data-set>
</data-sets>
<setup>
<simple-master-page name="MasterPage" id="2">
<footer>
<text id="3">
<prop name="contentType">html</prop>
<text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-prop>
</text>
</footer>
</simple-master-page>
</setup>
<body>
<table id="4">
<prop name="dataSet">set1</prop>
<list-prop name="boundDataColumns">
<struct>
<prop name="name">Name</prop>
<text-prop name="displayName">Name</text-prop>
<expression name="expression" type="javascript">dataSetRow["Name"]</expression>
<prop name="dataType">string</prop>
</struct>
<struct>
<prop name="name">City</prop>
<text-prop name="displayName">City</text-prop>
<expression name="expression" type="javascript">dataSetRow["City"]</expression>
<prop name="dataType">string</prop>
</struct>
<structure>
<prop name="name">Age</prop>
<text-prop name="displayName">Age</text-prop>
<expression name="expression" type="javascript">dataSetRow["Age"]</expression>
<prop name="dataType">integer</prop>
</structure>
</list-prop>
<column id="17"/>
<column id="18"/>
<column id="19"/>
<header>
<row id="5">
<cell id="6">
<label id="20">
<text-prop name="text">NameTitle</text-prop>
</label>
</cell>
<cell id="7">
<label id="21">
<text-prop name="text">CityTitle</text-prop>
</label>
</cell>
<cell id="8">
<label id="22">
<text-prop name="text">AgeTitle</text-prop>
</label>
</cell>
</row>
</header>
<detail>
<row id="9">
<cell id="10">
<data>
<prop name="resultSetColumn">Name</prop>
</data>
</cell>
<cell id="11">
<data>
<prop name="resultSetColumn">City</prop>
</data>
</cell>
<cell id="12">
<data>
<prop name="resultSetColumn">Age</prop>
</data>
</cell>
</row>
</detail>
</table>
</body>
</report>
Note: The encryptionID
and extensionID
both in data-source and data-set are fix values.
So basically the data comes from set set1
that uses source source1
, and it also comes directly from source1
, so I need to have a way of retrieving the correct data from the second XML file.
As you can see, I have can have many layout
and report
elements in the second XML file. So, first I think I need to find the displayName
property in the first XML file and then find the layout
element that in which the name
attribute matches displayName
. Then, I need to, in the second XML file, by the ID
attribute in layout
element, find the report
element that has that same value in the layoutID
attribute. From here on I would have found the correct report
element. Only now I would begin to change/make additions to the first XML file. This part I don't really know how to do. Is what I'm trying to do possible?
I know you can use the document
function to work with 2 XML files, but I don't really know how,
I really need help guys, thank you!
EDIT
I basically want to copy everything in the first XML file (already done) and then make additions to it with data stored in the second XML file (the one that starts with the <model>
element
UPDATE
Because I want the output to be an addition to the first input XML file, I started, as @Sojimanatsu recomended, by applying an identity transformation, like this (with @TimC's help on a post for the specific problem of the the special characters (XML - XSLT - Escape special characters) ):
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xmlbirtns="http://www.eclipse.org/birt/2005/design"
xpath-default-namespace="http://www.eclipse.org/birt/2005/design">
<xsl:output method="xml" omit-xml-declaration="no" indent="yes" encoding="utf-8" />
<xsl:strip-space elements="*"/>
<!--copy the whole input XML file-->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!--special treatment for setup/text-prop element-->
<xsl:template match="report/setup/simple-master-page/footer/text/text-prop">
<xsl:copy>
<xsl:attribute name="name">
<xsl:text>content</xsl:text>
</xsl:attribute>
<xsl:text disable-output-escaping="yes"><![CDATA[</xsl:text>
<xsl:value-of select="." disable-output-escaping="yes"/>
<xsl:text disable-output-escaping="yes">]]></xsl:text>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
NOTE: The XSLT code that deals with the setup/text-prop element is optional, because my output XML can have <value-of>new Date()</value-of>
instead of <![CDATA[<value-of>new Date()</value-of>]]>
So now I'm being able to print in the output XML exactly what I have in the first input XML. Now, as @Sojimanatsu said, I want to select specific tags and edit them with new data coming from the sencond input XML file, and I also want to add new tags/elements, like the data-sources
and data-sets
elements, but I don't know how to do this. I know I have to use the document() function but how??
To start, how can I add a new element, <data-sources>
below the <report>
element and before the <setup>
element? (<data-sources>
and <setup>
are siblings)
I tried doing this, adding a new <xsl:template>
:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xmlbirtns="http://www.eclipse.org/birt/2005/design"
xpath-default-namespace="http://www.eclipse.org/birt/2005/design">
<xsl:output method="xml" omit-xml-declaration="no" indent="yes" encoding="utf-8" />
<xsl:strip-space elements="*"/>
<!--copy the whole input XML file-->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!--special treatment for setup/text-prop element-->
<xsl:template match="report/setup/simple-master-page/footer/text/text-prop">
<xsl:copy>
<xsl:attribute name="name">
<xsl:text>content</xsl:text>
</xsl:attribute>
<xsl:text disable-output-escaping="yes"><![CDATA[</xsl:text>
<xsl:value-of select="." disable-output-escaping="yes"/>
<xsl:text disable-output-escaping="yes">]]></xsl:text>
</xsl:copy>
</xsl:template>
<xsl:template match="report/text-prop">
<xsl:copy-of select="."/>
<dataSources>DATA SOURCE VALUE</dataSources>
</xsl:template>
</xsl:stylesheet>
But I'm getting this output (the dataSource tag comes in the correct place but with some attributes that I don't know how got there):
<?xml version="1.0" encoding="utf-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.23" id="1">
<text-prop name="displayName">PersonTemplate</text-prop>
<dataSources xmlns=""
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xmlbirtns="http://www.eclipse.org/birt/2005/design">DATA SOURCE VALUE</dataSources>
<setup>
<simple-master-page name="MasterPage" id="2">
<footer>
<text id="3">
<prop name="contentType">html</prop>
<text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-prop>
</text>
</footer>
</simple-master-page>
</setup>
<body>
<table id="4">
<column id="17"/>
<column id="18"/>
<column id="19"/>
<header>
<row id="5">
<cell id="6">
<label id="20">
<text-prop name="text">NameTitle</text-prop>
</label>
</cell>
<cell id="7">
<label id="21">
<text-prop name="text">CityTitle</text-prop>
</label>
</cell>
<cell id="8">
<label id="22">
<text-prop name="text">AgeTitle</text-prop>
</label>
</cell>
</row>
</header>
<detail>
<row id="9">
<cell id="10"/>
<cell id="11"/>
<cell id="12"/>
</row>
</detail>
</table>
</body>
</report>
My real first and second input XML files are considerably bigger but once I have this example working I can produce my real XML output,
Thanks guys!