Skip to content
This repository has been archived by the owner on Nov 18, 2024. It is now read-only.

Commit

Permalink
Needed to make changes to the Site Inventory workbook generation code…
Browse files Browse the repository at this point in the history
… to account for new Tableau Workbook XML format changes. Data Source XML definitions are now all 'federated' data sources. This results in the need for more complex code to find/replace the template XML.
  • Loading branch information
unknown authored and unknown committed May 8, 2017
1 parent dd9b7e3 commit fdf8464
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 273 deletions.
2 changes: 1 addition & 1 deletion TabRESTMigrate/TabRESTMigrate.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<WebPage>publish.htm</WebPage>
<ApplicationRevision>12</ApplicationRevision>
<ApplicationRevision>13</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
Expand Down
2 changes: 1 addition & 1 deletion TabRESTMigrate/TaskManager/TaskMaster.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1148,7 +1148,7 @@ private void Execute_GenerateSiteInventoryFile_Twb(string pathReportCsv)
var twbGenerateFromTemplate = new TwbReplaceCSVReference(
PathHelper.GetInventoryTwbTemplatePath(), //*.twb we are using as our template
pathTwbOut, //Output *.twb we are generating
"siteInventory", //Datasource name in tempalte workbook
"siteInventoryTemplate.csv", //Datasource filename in tempalte workbook
pathReportCsv, //CSV file we want to associate with the datasource above
_statusLog);

Expand Down
82 changes: 53 additions & 29 deletions TabRESTMigrate/WorkbookTransforms/TwbReplaceCSVReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class TwbReplaceCSVReference
{
private readonly string _pathToTwbInput;
private readonly string _pathToTwbOutput;
private readonly string _datasourceName;
private readonly string _oldDatasourceFilename;
private readonly string _datasourceNewCsvPath;
private readonly TaskStatusLogs _statusLog;

Expand All @@ -21,14 +21,14 @@ class TwbReplaceCSVReference
/// </summary>
/// <param name="pathTwbInput">TWB we are going to load and transform</param>
/// <param name="pathTwbOutput">Output path for transformed CSV</param>
/// <param name="dataSourceName">Name of data source inside path</param>
/// <param name="oldDatasourceFilename">Old filename for the data source (case insensitive)</param>
/// <param name="newCsvPath">Path to CSV file that we want the data source to point to</param>
/// <param name="statusLog">Log status and errors here</param>
public TwbReplaceCSVReference(string pathTwbInput, string pathTwbOutput, string dataSourceName, string newCsvPath, TaskStatusLogs statusLog)
public TwbReplaceCSVReference(string pathTwbInput, string pathTwbOutput, string oldDatasourceFilename, string newCsvPath, TaskStatusLogs statusLog)
{
_pathToTwbInput = pathTwbInput;
_pathToTwbOutput = pathTwbOutput;
_datasourceName = dataSourceName;
_oldDatasourceFilename = oldDatasourceFilename;
_datasourceNewCsvPath = newCsvPath;
_statusLog = statusLog;
}
Expand All @@ -45,7 +45,7 @@ public bool Execute()
xmlDoc.Load(_pathToTwbInput);

bool foundReplaceItem =
RemapDatasourceCsvReference(xmlDoc, _datasourceName, _datasourceNewCsvPath, _statusLog);
RemapDatasourceCsvReference(xmlDoc, _oldDatasourceFilename, _datasourceNewCsvPath, _statusLog);

//Write out the transformed XML document
TableauPersistFileHelper.WriteTableauXmlFile(xmlDoc, _pathToTwbOutput);
Expand All @@ -56,47 +56,71 @@ public bool Execute()
/// Finds and changes a datasource reference inside a Workbook. Changes the CSV file the data source points to
/// </summary>
/// <param name="xmlDoc"></param>
/// <param name="datasourceName"></param>
/// <param name="oldDatasourceFilename">Filenane (without path) of the datasource we want to replace. Case insensitive</param>
/// <param name="pathToTargetCsv"></param>
/// <param name="statusLog"></param>
private bool RemapDatasourceCsvReference(XmlDocument xmlDoc, string datasourceName, string pathToTargetCsv, TaskStatusLogs statusLog)
private bool RemapDatasourceCsvReference(XmlDocument xmlDoc, string oldDatasourceFilename, string pathToTargetCsv, TaskStatusLogs statusLog)
{
int replaceItemCount = 0;
string newCsvDirectory = Path.GetDirectoryName(_datasourceNewCsvPath);
string newCsvFileName = Path.GetFileName(_datasourceNewCsvPath);
string newDatasourceRelationName = Path.GetFileNameWithoutExtension(newCsvFileName) + "#csv";
string newDatasourceRelationTable = "[" + newDatasourceRelationName + "]";
string seekDatasourceCaption = _datasourceName;

var xDataSources = xmlDoc.SelectNodes("workbook/datasources/datasource");
if(xDataSources != null)
{
//Look through the data sources
foreach (XmlNode xnodeDatasource in xDataSources)
{
//If the data source is matching the caption we are looking for
if(XmlHelper.SafeParseXmlAttribute(xnodeDatasource, "caption", "") == seekDatasourceCaption)
var xConnections = xnodeDatasource.SelectNodes(".//connection");
if (xConnections != null)
{
var xnodeConnection = xnodeDatasource.SelectSingleNode("connection");
//It should be 'textscan', it would be unexpected if it were not
if(XmlHelper.SafeParseXmlAttribute(xnodeConnection, "class", "") == "textscan")
foreach (XmlNode xThisConnection in xConnections)
{
//Point to the new directory/path
xnodeConnection.Attributes["directory"].Value = newCsvDirectory;
xnodeConnection.Attributes["filename"].Value = newCsvFileName;

//And it's got a Relation we need to update
var xNodeRelation = xnodeConnection.SelectSingleNode("relation");
xNodeRelation.Attributes["name"].Value = newDatasourceRelationName;
xNodeRelation.Attributes["table"].Value = newDatasourceRelationTable;

replaceItemCount++;
}
else
{
_statusLog.AddError("Data source remap error. Expected data source to be 'textscan'");
}
}//end if
//If its a 'textscan' (CSV) and the file name matches the expected type, then this is a datasource's connection we want to remap
//to point to a new CSV file
if ((XmlHelper.SafeParseXmlAttribute(xThisConnection, "class", "") == "textscan") &&
(string.Compare(XmlHelper.SafeParseXmlAttribute(xThisConnection, "filename", ""),
oldDatasourceFilename, true) == 0))
{

//Find any relation nodes beneath the datasource
//Newer version of the document model put the textscan connection inside a federated data source
//to deal with that, we need to look upward from the connection and adjacent in the DOM to find the correct
//node to replace. This is done by looking at child nodes in the datasource
var xNodeAllConnectionRelations = xnodeDatasource.SelectNodes(".//relation");
XmlNode xNodeRelation = null;
if (xNodeAllConnectionRelations != null)
{
if(xNodeAllConnectionRelations.Count == 1)
{
xNodeRelation = xNodeAllConnectionRelations[0];
}
else
{
statusLog.AddError("CSV replacement. Expected 1 Relation in data source definition, actual " + xNodeAllConnectionRelations.Count.ToString());
}
}


//Only if we have all the elements need to replace, should we go ahead with the replacement
if ((xNodeRelation != null) && (xThisConnection != null))
{
//Point to the new directory/path
xThisConnection.Attributes["directory"].Value = newCsvDirectory;
xThisConnection.Attributes["filename"].Value = newCsvFileName;

xNodeRelation.Attributes["name"].Value = newDatasourceRelationName;
xNodeRelation.Attributes["table"].Value = newDatasourceRelationTable;

replaceItemCount++;
}
}

}//end: foreach xThisConnection
}

}//end foreach
}//end if

Expand Down
7 changes: 7 additions & 0 deletions TabRESTMigrate/_SampleFiles/ReadMe.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
NOTE:
The Tableau Workbook in this directory (SiteInventory.twb) is used as a template from which the Site Inventory Workbookis generated.

If you want to edit the Tableau Workbook, MAKE SURE you have it point to a sample *.csv file named 'siteInventoryTemplate.csv'.
The TabMigrate code that generates the Site Inventory workbook looks for and replaces the data file references to
'siteInventoryTemplate.csv' in this template workbook. If the Workbook is saved with a reference to another file name the search/replace
will not work and the result will be a Tableau Workbook that does NOT point to the data of the exported site.
Loading

0 comments on commit fdf8464

Please sign in to comment.