How to apply two different transformations on one web.config element? - visual-studio-2010

From my VS2010 deployment project I would like to apply two different transformations to two different attributes of one element in my web.config. Consider the following web.config snippet:
<exampleElement attr1="false" attr2="false" attr3="true" attr4="~/" attr5="false">
<supportedLanguages>
<!-- Some more elements here -->
</supportedLanguages>
</exampleElement>
Now how can I change attribute 'attr1' and remove attribute 'attr5' in the transformed web.config? I know how to perform the individual transformations:
<exampleElement attr1="true" xdt:Transform="SetAttributes(attr1)"></exampleElement>
and:
<exampleElement xdt:Transform="RemoveAttributes(attr5)"></exampleElement>
But I don't know how to combine these transforms. Anybody?
EDIT:
Can't answer my own question yet, but the solution seems to be:
It seems that it is possible to repeat the same element with different transformations, like so:
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<exampleElement attr1="true" xdt:Transform="SetAttributes(attr1)"></exampleElement>
<exampleElement xdt:Transform="RemoveAttributes(attr5)"></exampleElement>
</configuration>
As said, this seems to work, but I'm not sure whether this is the intended use of the web.config transformation syntax.

As Nick Nieslanik confirmed this is done by repeating the same element with different transformations, like so:
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<exampleElement attr1="true" xdt:Transform="SetAttributes(attr1)"></exampleElement>
<exampleElement xdt:Transform="RemoveAttributes(attr5)"></exampleElement>
</configuration>

I'm using XmlPreprocess tool for config files transformations & manipulation. It is using one mapping file for multiple environments. You can edit mapping file by Excel. It is very easy to use.
You can update your config files with xmlpreprocess and use configuration (debug, dev, prod,...) as a parameter for the different setup...

Related

How do I replace part of a path in my web.config transform?

I am trying to perform a web.config transform in Visual Studio 2022 by modifying the web.Debug.config file.
Changing attributes on elements, removing elements and attributes, etc. is all very straightforward. But I've a read through this document and I've done some Google searching, and I cannot figure out a way to replace part of a path string in my web.config file.
Given that I have lots of NLog target elements is there an easy way to replace the root path in the fileName and archiveFileName attributes for each?
Here is where I am coming from:
<target xsi:type="File" name="seedDataLogFile"
fileName="C:/ProductionPath/Logs/seedDataCurrent.json"
archiveFileName="C:/ProductionPath/Logs/SeedDataArchive/{#}.json"
archiveEvery="Day" archiveNumbering="Date" archiveDateFormat="yyyy-MM-dd" maxArchiveFiles="60"
concurrentWrites="true" keepFileOpen="false">
And here is where I want to go:
<target xsi:type="File" name="seedDataLogFile"
fileName="D:/DevelopmentPath/Logs/seedDataCurrent.json"
archiveFileName="D:/DevelopmentPath/Logs/SeedDataArchive/{#}.json"
archiveEvery="Day" archiveNumbering="Date" archiveDateFormat="yyyy-MM-dd" maxArchiveFiles="60"
concurrentWrites="true" keepFileOpen="false">
Thanks for your help.

Apache Nifi - move a top-level element into children (JSON/XML)

New to Apache Nifi and trying to process an XML that looks a bit like this:
<?xml version="1.0" encoding="iso-8859-1"?>
<productCatalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<version>CHANNELS-VERSION-100</version>
<channels>
<channel>
<id>1</id>
<name>Super Channel 1</name>
</channel>
<channel>
<id>2</id>
<name>Super Channel 2</name>
</channel>
</channels>
</productCatalog>
What I want, is to read the "version" element, then include it in the "channel" children when I process them further down the pipeline e.g. to produce something like this (in XML or JSON):
<processedChannel>
<catalogVersion>CHANNELS-VERSION-100</catalogVersion>
<id>2</id>
<name>Super Channel 2</name>
</processedChannel>
I've tried various permutations of XQuery, XMLSplit, UpdateAttribute to put the version in a flow attribute (not content),etc, but I cannot seem to make the "version" available for all the "channels" downstream. I can either get a flow that only contains the version, or I can get the channels, but I cannot find a way to combine them.
This seems like it should be easy, but I cannot find an obvious solution.
My real use case has a really big XML file, so I am trying to avoid loading it all in one go - I split it as early as possible so I can stream the children more easily. That's why I want to put the version onto the children if possible.
Any help gratefully received!
ForkRecord should do what you want. From your desired output I think you'll want "extract" as the mode, but you could try both and see what you get for output. ForkRecord and the XML Reader/Writer are available as of NiFi 1.7.0.
#mattyb: Thanks for your suggestions. ForkRecord looks really interesting, but doesn't fit with my current use case because it needs a schema. But the EvaluateXPath and EvaluateXQuery options both seem to work now, even though I spent hours playing around with these previously.
Here's my flow now:
ListFile --> FetchFile --> Evaluate XPath (to get version as flow-file attribute) --> SplitXml --> etc - and now I have the version in my flow-file attributes for the downstream processing, which was what was wanted.
Not sure why it didn't work before, but thanks for prompting me to look at it again.

Using CombresMvc with TelerikMvc

I am using the Combres combiner/minifier NuGet package. I am also using the following filters:
<filters>
<!-- This filter allows relative urls to be used in Css files like in .NET; e.g. "~/MyFolder/MyPic.png"-->
<filter type="Combres.Filters.FixUrlsInCssFilter, Combres" />
<!-- This filter allows you to define variables in a CSS file and reuse them throughout the file. -->
<filter type="Combres.Filters.HandleCssVariablesFilter, Combres" />
<!-- This filter changes Combres order of ops so that common css variables can be defined in a single
file and used throughout multiple css files, instead of having to define them in each file. -->
<filter type="Combres.Filters.DotLessCssCombineFilter, Combres" />
</filters>
This allows me to define a single CssVariables.css file, and use those variables in any of the other css files (by default, you would have to have variable definitions in each css file, which uses the DotLessCssFilter).
Using the DotLessCssCombineFilter changes the order of operations in Combres so that files are combined FIRST and then variables replaced in the combined file output.
All works extremely well, until I set up the resource set for the telerik stylesheets.
Specifically, it is just the telerik.common.min.css file with an issue. That issue appears on the line:
html .t-dirty{border-color:#f00 pink pink #f00;filter:chroma(color=pink)}
The offending attribute is the: filter:chroma(color=pink)
Removing that attribute stops a null error from occurring in the combres.axd that stops all processing. That attribute is only used on that line in the entire file (and no where else from what I can tell).
All will work well if you remove that attribute.
Enjoy!!
The answer is in the question. I just wanted to share this so no one else had to go through the telerik css file line by line like I did to isolate the issue!
:)
Enjoy!

Replacing one XML element with another

I'm interested in finding out what's the shortest script one can write to replace one XML element in a file with another one from a second file.
I can whip up a simple program to easily do this, but I'm wondering if it's easily do-able using a shell script. It's just a utility tool meant as a convenience. Can this be done using sed? awk? I'm not familiar with those. I suppose I can probably do it with a combination of grep and wc, but it seems likely that there's a much more direct way to do this.
Essentially, I have a large configuration file, say config.xml, which say looks like this:
<config>
<element name="a">
<subelement />
</element>
<element name="b">
<subelement />
</element>
<element name="c">
<subelement />
</element>
<!-- and so on... -->
</config>
Once in a while, changes require me to modify/add/delete one subelement. Now, it so happens that there's a sort of generator that will generate an up-to-date subconfig.xml, like following file:
<config>
<element name="c">
<subelement />
<subelement />
</element>
</config>
My thinking is that if I can take the element in subconfig.xml and replace the existing one in config.xml, then hey, that'd be great! Yea, it's not much a work-saver, since it's only needed rarely, but it just occurred to me that I could try to do it in a script, but I'm not sure how.
Any help appreciated (including pointing out that I'd be better off writing a program for this ^-^).
If your xml are consistent and your replacement requirement is simple, there's actually no need to use parsers. Just simple awk will do
$ subconfig=(<subconfig.xml)
$ awk -v subconf=$subconfig '/<config>/{print subconf}/<config>/,/<\/config>/{next}1' config.xml
I wouldn't attempt to do this with command-line tools, you'll run into all sorts of difficulties. The way you should do this is with a proper XML parser. The logic would be: consume original file, parse it, consume update file, parse it, identify which node this guy is to replace, do the replace, write out the result.
I don't know what you are comfortable with coding-wise, but there's XML parsers available in most popular languages.

How to have global settings defined in a solution in VC++?

I have a number of solutions with a large number of projects in them. I would like to be able to define global settings for the solution that are used by all projects. For example an include directory. I want to be able to change the include directory in one place for all projects in the solutions.
When I searched for a solution I found a good description of the problem that matches mine exactly but the solution suggested there, project property sheets, are defined per project and not per solutions.
I could use environment variables or Visual studio settings, but then everyone that needs to compile the code has to define the exact same settings.
Can anyone suggest a way to do this? Thanks.
We use property sheets to accomplish this. A single property sheet can be assigned to all the projects in the solution. From then on you can change a setting in that one property sheet and it will affect all the projects.
Advanced tip: We actually use multiple property sheets, (e.g. one for release target types, one for debug target types). The tip is that the order is very important. If you're editing the project files by hand then the last property sheet will override settings in the previous property sheets in the list. If you're editing in the GUI, then the TOP one overrides the ones below it.
As others have suggested, property sheets can do what you want. The trick is to use InheritedPropertySheets as you would use #include in C++. NOTE: the XML is slightly different for project files and property sheet files. Here's a contrived and simplified example of two projects (prjA.vcproj and prjB.vcproj) including the same property sheet (sln.vsprops) which itself includes another (strict.vsprops):
strict.vsprops
<VisualStudioPropertySheet ...>
<Tool Name="VCCLCompilerTool" WarningLevel="3" WarnAsError="true"/>
</VisualStudioPropertySheet>
sln.vsprops
<VisualStudioPropertySheet ... InheritedPropertySheets=".\strict.vsprops">
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="NOMINMAX=1"
RuntimeTypeInfo="true"
/>
</VisualStudioPropertySheet>
prjA.vcproj
<VisualStudioProject ...>
<Configurations>
<Configuration ... InheritedPropertySheets=".\sln.vsprops">
</Configuration>
</Configurations>
...
</VisualStudioProject>
prjB.vcproj
<VisualStudioProject ...>
<Configurations>
<Configuration ... InheritedPropertySheets=".\sln.vsprops">
</Configuration>
</Configurations>
...
</VisualStudioProject>
You may also find this question and its answers useful.
Maybe you could add an MSBuild file to your solution in which you define a number of shared properties, and then <Import> that file into all your real projects?
That is, in your "settings" MSBuild file you define a number of properties:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WinUnitIncludeDir>C:\Includes\WinUnit</WinUnitIncludeDir>
<!-- Other shared properties go here -->
</PropertyGroup>
</Project>
From your real projects, you can then refer to this:
<Project ...>
...
<Import Project="path/to/settings.msbuild" />
...
<Configurations>
<Configuration ...>
<Tool Name="VCCLCompilerTool"
...
AdditionalIncludeDirectories="$(WinUnitIncludeDir)"
... />
...
...
...
</Project>
As suggested, you should look at Property Sheets (aka .vsprops files).
I wrote a very short introduction to this feature here.
I searched exactly the same thing some time ago but didn't find exactly what i wanted.
The only thing that might be close to this feature are Property Sheets. That's not exactly global as it's owned by a project and used by others.

Resources