XSLT Change attribute value of specific elements with a condition - xpath

I have the following XML content:
<fragment>
<directory Id="dirABC" Name="ABC">
<component Id="cmpA" Guid="*">
<file Id="filA" KeyPath="yes" Source="SourceRootDir\AAA.exe" />
</component>
<component Id="cmpB" Guid="*">
<file Id="filB" KeyPath="yes" Source="SourceRootDir\BBB.exe" />
</component>
<component Id="cmpC" Guid="*">
<file Id="filC" KeyPath="yes" Source="SourceRootDir\CCC.exe" />
</component>
</directory>
</fragment>
I am trying to find the file elements that have the Source attribute ending with 'BBB.exe' and replace its Id attribute with another value, e.g. with filNEW. In my example the Id attribute value 'filB' should be changed to 'filNEW'. So, my XSLT is defined the following way:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output omit-xml-declaration="no" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/fragment/directory/component/file[substring(#Source, string-length(#Source) - string-length('BBB.exe') + 1) = 'BBB.exe']">
<xsl:attribute name="Id">filNEW</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
However, instead of updating only the Id attribute of the file element of the second component element, the result has the whole file element removed for the second component and has the component element's Id attribute value replaced with the new filNEW value. The current result.
<?xml version="1.0" encoding="UTF-8"?>
<fragment>
<directory Id="dirABC" Name="ABC">
<component Guid="*" Id="cmpA">
<file Id="filA" KeyPath="yes" Source="SourceRootDir\AAA.exe"/>
</component>
<component Guid="*" Id="filNEW"/>
<component Guid="*" Id="cmpC">
<file Id="filC" KeyPath="yes" Source="SourceRootDir\CCC.exe"/>
</component>
</directory>
</fragment>
Whereas, I am trying to get this result:
<?xml version="1.0" encoding="UTF-8"?>
<fragment>
<directory Id="dirABC" Name="ABC">
<component Guid="*" Id="cmpA">
<file Id="filA" KeyPath="yes" Source="SourceRootDir\AAA.exe"/>
</component>
<component Id="cmpB" Guid="*">
<file Id="filNEW" KeyPath="yes" Source="SourceRootDir\BBB.exe" />
</component>
<component Guid="*" Id="cmpC">
<file Id="filC" KeyPath="yes" Source="SourceRootDir\CCC.exe"/>
</component>
</directory>
</fragment>
What am I doing wrong in the XSLT?

You are matching on the file element and then generating an attribute. If you just want to replace the value of the #Id attribute, then change your match expression to match on that #Id by adding /#Id after the predicate on the file:
<xsl:template match="/fragment/directory/component/file[substring(#Source, string-length(#Source) - string-length('BBB.exe') + 1) = 'BBB.exe']/#Id">
<xsl:attribute name="Id">filNEW</xsl:attribute>
</xsl:template>

Related

Get absolute path of FILE in WiX

I got the following file in WiX:
<Component Id='MainExecutable' Guid='91C8C2C0-59AF-4BDD-A78D-C4369DD4CD81'>
<File Id='FoobarEXE' Name='FoobarAppl10.exe' Source='FoobarAppl10.exe' KeyPath='yes'>
</File>
</Component>
<Component Id="ProgramMenuDir" Guid="D3B0871E-A86D-4692-B419-AE2A2A578648">
<RegistryValue Root='HKCR' Key='conversationwindowaction\shell\open\command' Type='string' Value='"[absolute path to exe]" "%1"' KeyPath='yes' />
</Component>
I want [absolute path to exe] be the string to the path of FoobarEXE, how can I do this?
<Component Id="ProgramMenuDir" Guid="D3B0871E-A86D-4692-B419-AE2A2A578648">
<RegistryValue Root='HKCR' Key='conversationwindowaction\shell\open\command' Type='string' Value='"[#FoobarEXE]" "%1"' KeyPath='yes' />
</Component>
You need to enclose the file id in [#fileid] see example above.

WiX "Undefined Preprocessor Variable" despite variable in .wxi file

I have a WiX project in visual studio that contains two files: Product.wxs and config.wxi.
When I attempt to build this project, I get the following error: "Undefined preprocessor variable '$(var.ProductName)'."
What am I doing wrong here that the Include file is apparently not being recognized?
config.wxi
<?xml version="1.0" encoding="utf-8"?>
<Include>
<?Define Manufacturer = "My Company" ?>
<?Define ProductName = "My Product" ?>
<?Define Version = "1.0.0.0" ?>
<?Define BuildType = "Development" ?>
<?Define BuildTypeShort = "Dev" ?>
</Include>
Product.wxs:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<?include config.wxi ?>
<Product Id="*" Name="$(var.ProductName)" Language="1033" Version="$(var.Version)" Manufacturer="$(var.Manufacturer)" UpgradeCode="6e7efd44-0149-416b-871d-418ba6365e1b">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<Feature Id="ProductFeature" Title="MySetup" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="ManufacturerFolder" Name="$(var.Manufacturer)">
<Directory Id="INSTALLFOLDER" Name="$(var.ProductName)" />
</Directory>
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="ProductComponent">
<File Source="$(var.SomeProjectA.TargetPath)"/>
<File Source="$(var.SomeProjectB.TargetPath)"/>
</Component>
</ComponentGroup>
</Fragment>
</Wix>
Use "define" instead of "Define".
As here:
<?xml version="1.0" encoding="utf-8"?>
<Include>
<?define Manufacturer = "My Company" ?>
<?define ProductName = "My Product" ?>
<?define Version = "1.0.0.0" ?>
<?define BuildType = "Development" ?>
<?define BuildTypeShort = "Dev" ?>
</Include>

Add creation of shortcut menus option to the default WixUI_Mondo template

I have the following (default) markup for my WiX installer project:
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder' Name='PFiles'>
<Directory Id='Acme' Name='Acme'>
<Directory Id='INSTALLDIR' Name='Foobar 1.0'>
<Component Id='MainExecutable' Guid='*'>
<File Id='FoobarEXE' Name='FoobarAppl10.exe' DiskId='1'
Source='FoobarAppl10.exe' KeyPath='yes'>
<Shortcut Id="startmenuFoobar10" Directory="ProgramMenuDir"
Name="Foobar 1.0" WorkingDirectory='INSTALLDIR'
Icon="Foobar10.exe" IconIndex="0" Advertise="yes" />
<Shortcut Id="desktopFoobar10" Directory="DesktopFolder"
Name="Foobar 1.0" WorkingDirectory='INSTALLDIR'
Icon="Foobar10.exe" IconIndex="0" Advertise="yes" />
</File>
</Component>
<Component Id='HelperLibrary' Guid='*'>
<File Id='HelperDLL' Name='Helper.dll' DiskId='1'
Source='Helper.dll' KeyPath='yes' />
</Component>
<Component Id='Manual' Guid='*'>
<File Id='Manual' Name='Manual.pdf' DiskId='1'
Source='Manual.pdf' KeyPath='yes'>
<Shortcut Id="startmenuManual" Directory="ProgramMenuDir"
Name="Instruction Manual" Advertise="yes" />
</File>
</Component>
</Directory>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder" Name="Programs">
<Directory Id="ProgramMenuDir" Name="Foobar 1.0">
<Component Id="ProgramMenuDir" Guid="*">
<RemoveFolder Id='ProgramMenuDir' On='uninstall' />
<RegistryValue Root='HKCU' Key='Software\[Manufacturer]\[ProductName]'
Type='string' Value='' KeyPath='yes' />
</Component>
</Directory>
</Directory>
<Directory Id="DesktopFolder" Name="Desktop" />
</Directory>
It compiles into the following MSI:
I'm wondering, can I add "Create desktop shortcuts" option to that installation tree so that users could select or remove it?
You just need to move the Shortcut elements into their own component(s), and add those to a new Feature.
This guide does it that way: How To: Create a Shortcut on the Start Menu

How to create a sub folder in installation folder using WiX

How to create a sub folder in installation folder(which in my case is named WWU)? I am creating an installation folder named WWU in Program Files, I want to create a sub folder named image inside WWU folder which will contain some necessary images files. I tried doing so using below code but I am unable to get folder being created.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="{AADE647C-36C5-48A7-A88F-5AB8D6BAE7FE}" Name="WWU 1.0" Language="1033" Version="1.0.0.0" Manufacturer="Aricent Group" UpgradeCode="f89a1900-bdb0-4fec-a035-e69ae882716b">
<Package Id="*" Keywords="Installer" Description="Aricent's WWU 1.0 Installer" Comments="WWU is a registered trademark of Aricent Group." Manufacturer="Aricent Group" InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<UIRef Id="WixUI_Minimal"/>
<WixVariable Id="WixUILicenseRtf" Value="$(var.WWU_UI.TargetDir)License.rtf"/>
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<Media Id= "1" Cabinet="WWU.cab" EmbedCab="yes"/>
<Feature Id="Complete" Title="WWU`_Installer" Description="The complete package." Display="expand" ConfigurableDirectory="INSTALLFOLDER" Level="1">
<ComponentGroupRef Id="ProductComponents"/>
<ComponentGroupRef Id="Shortcuts"/>
</Feature>
<Feature Id="ImagePack" Title="Images" Level="1">
<ComponentGroupRef Id="ImageFiles"/>
</Feature>
</Product>
<Fragment>
<UI>
<Dialog Id="UserRegistrationDlg" Width="360" Height="250" Title="[ProductName] Setup" NoMinimize="yes">
<Control Id="NameLabel" Type="Text" X="45" Y="70" Width="100" Height="15" TabSkip="no" Text="User Name:"/>
<Control Id="NameEdit" Type="Text" X="45" Y="80" Width="220" Height="18" Property="USERNAME" Text="{80}" />
<Control Id="OrganizationalLabel" Type="Text" X="45" Y="110" Width="100" Height="15" TabSkip="no" Text="Organization:"/>
</Dialog>
</UI>
</Fragment>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="WWU" />
</Directory>
<Directory Id="ProgramMenuFolder" Name="Programs">
<Directory Id="ProgramMenuDir" Name="WWU 1.0" />
</Directory>
<Directory Id="DesktopFolder" Name="Desktop" />
<Directory Id="ImageFolder" Name="image"/>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
<Component Id="MainExecutable" Guid="{434D54CC-D875-4B45-8125-CCCB8119A053}">
<!-- TODO: Insert files, registry keys, and other resources here. -->
<File Id="WWUEXE" Name="WWU_UI.exe" Source="$(var.WWU_UI.TargetDir)WWU_UI.exe" KeyPath="yes">
<Shortcut Id="startmenuWWU" Directory="ProgramMenuDir" Name="WWU Tutorial 1.0" WorkingDirectory="IINSTALLDIR" Icon="WWU_UI.exe" Advertise="yes"/>
<Shortcut Id="desktopWWU" Directory="DesktopFolder" Name="WWU Tutorial 1.0" WorkingDirectory="IINSTALLDIR" Icon="WWU_UI.exe" Advertise="yes"/>
</File>
</Component>
<Component Id="SQLiteInterop" Guid="{7DBF7C38-3001-403F-911E-AF3C318F6219}">
<File Id="Interopdll" Name="SQLite.Interop.dll" Source="$(var.WWU_UI.TargetDir)x86\SQLite.Interop.dll" />
</Component>
<Component Id="SQLitedll" Guid="{DB1FB7CC-6D89-478B-9276-8F4F987027AC}" >
<File Id="SQLite" Name="System.Data.SQLite.dll" Source="$(var.WWU_UI.TargetDir)System.Data.SQLite.dll" />
</Component>
<Component Id="SQLiteLinqdll" Guid="{C65A7DD8-6F1A-4E02-86B2-2B2EDFFDD684}" >
<File Id="SQLiteLinq" Name="System.Data.SQLite.Linq.dll" Source="$(var.WWU_UI.TargetDir)System.Data.SQLite.Linq.dll" />
</Component>
<Component Id="Log4net" Guid="{5266C74E-D7F8-4091-90C2-B661A63B7909}" >
<File Id="Log4netdll" Name="log4net.dll" Source="$(var.WWU_UI.TargetDir)log4net.dll" />
</Component>
</ComponentGroup>
<ComponentGroup Id="Shortcuts" Directory="ProgramMenuDir">
<Component Id="ProgramMenuShortcut">
<RemoveFolder Id="ProgramMenuDir" On="uninstall" />
<RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]" Type="string" Value="" KeyPath="yes" />
</Component>
</ComponentGroup>
<!-- image files for image folder -->
<ComponentGroup Id="ImageFiles" Directory="ImageFolder">
<Component Id="Asfo" Guid="{B8031331-076F-4C75-B231-3EBCBBD8D29C}">
<File Id="Asfoimg" Name="0sf0.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\0sfo.ico" />
</Component>
<Component Id="Asfob" Guid="{D0D78785-3CFC-49C7-9470-90250034D331}">
<File Id="Asfobimg" Name="0sfob.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\0sfob.ico" />
</Component>
<Component Id="Aufo" Guid="{6912A60F-F612-4AB8-B530-A0EA71AF8587}">
<File Id="Aufoimg" Name="0ufo.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\0ufo.ico" />
</Component>
<Component Id="Aufob" Guid="{AD38A28F-3518-4AA4-B169-EC5077844E83}">
<File Id="Aufobimg" Name="0ufob.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\0ufob.ico" />
</Component>
<Component Id="Bsfo" Guid="{D9A2BD2E-70C2-47DE-8B20-501A9D77A3CD}">
<File Id="Bsfoimg" Name="1sfo.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\1sfo.ico" />
</Component>
<Component Id="Bsfob" Guid="{AC063280-4698-4605-B74C-471DEAD9D595}">
<File Id="Bsfobimg" Name="1sfob.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\1sfob.ico" />
</Component>
<Component Id="Bufo" Guid="{0D840A42-3119-4283-9220-BCD722FA4D31}">
<File Id="Bufoimg" Name="1ufo.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\1ufo.ico" />
</Component>
<Component Id="Bufob" Guid="{A8425CC9-5787-419D-8D37-8B6F16726C84}">
<File Id="Bufobimg" Name="1ufob.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\1ufob.ico" />
</Component>
<Component Id="Csfo" Guid="{CBB6870F-3FBA-4ADC-B508-D865A8642C19}">
<File Id="Csfoimg" Name="2sfo.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\2sfo.ico" />
</Component>
<Component Id="Csfob" Guid="{E0EBE823-11EB-4054-A544-1F9859D06A00}">
<File Id="Csfobimg" Name="2sfob.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\2sfob.ico" />
</Component>
<Component Id="Cufo" Guid="{E1870A35-B398-4B4A-AC1C-0A701A5188F8}">
<File Id="Cufoimg" Name="2ufo.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\2ufo.ico" />
</Component>
<Component Id="Cufob" Guid="{3A6EA0AE-38C0-496C-B977-3342F3C6D8B8}">
<File Id="Cufobimg" Name="2ufob.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\2ufob.ico" />
</Component>
<Component Id="Dsfo" Guid="{2D575CA7-96DA-40A1-B1EC-173F455E47C4}">
<File Id="Dsfoimg" Name="3sfo.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\3sfo.ico" />
</Component>
<Component Id="Dsfob" Guid="{C08977BB-8FF7-459F-B3B3-8A9E75152EF5}">
<File Id="Dsfobimg" Name="3sfob.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\3sfob.ico" />
</Component>
<Component Id="Dufo" Guid="{552B1B41-247D-490B-9433-B642CAD6A70A}">
<File Id="Dufoimg" Name="3ufo.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\3ufo.ico" />
</Component>
<Component Id="Dufob" Guid="{3140C586-45C8-4496-BADD-3F55D9F2B751}">
<File Id="Dufobimg" Name="3ufob.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\3ufob.ico" />
</Component>
<Component Id="Esfo" Guid="{311F89D5-5E53-4B45-87F7-B521ACC6D7C1}">
<File Id="Esfoimg" Name="4sfo.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\4sfo.ico" />
</Component>
<Component Id="Esfob" Guid="{E9239C1D-3F5A-497B-92D4-0830E739A5E9}">
<File Id="Esfobimg" Name="4sfob.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\4sfob.ico" />
</Component>
<Component Id="Eufo" Guid="{8A057476-D9B3-4033-9906-567377D97304}">
<File Id="Eufoimg" Name="4ufo.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\4ufo.ico" />
</Component>
<Component Id="Eufob" Guid="{8CE17A52-19B1-4FB6-9D12-0B231E3DDE4D}">
<File Id="Eufobimg" Name="4ufob.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\4ufob.ico" />
</Component>
<Component Id="Fsfo" Guid="{D0433C83-BCC5-41EB-8015-9D76E4457448}">
<File Id="Fsfoimg" Name="5sfo.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\5sfo.ico" />
</Component>
<Component Id="Fsfob" Guid="{C65BD8E6-C9F1-4A75-9A23-3A6DB35B4BFC}">
<File Id="Fsfobimg" Name="5sfob.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\5sfob.ico" />
</Component>
<Component Id="Fufo" Guid="{4F9D5939-7011-4D99-A65B-3F0A2130622B}">
<File Id="Fufoimg" Name="5ufo.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\5ufo.ico" />
</Component>
<Component Id="Fufob" Guid="{90D7B520-4A37-42AC-AB62-F5485A89FCC9}">
<File Id="Fufobimg" Name="5ufob.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\5ufob.ico" />
</Component>
<Component Id="Ari_WWU" Guid="{086B969B-BAA2-4DFA-B699-F56FF885AB26}">
<File Id="Ari_WWUimg" Name="Ari_WWU.ico" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\Ari_WWU.ico" />
</Component>
<Component Id="auto" Guid="{9625F82B-B206-40E6-9310-8D46563E20C6}">
<File Id="auto" Name="auto.png" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\auto.png" />
</Component>
<Component Id="info" Guid="{DDCBB410-77DD-49C9-9372-98DD2747121E}">
<File Id="infoimg" Name="info.png" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\info.png" />
</Component>
<Component Id="manual" Guid="{4F8768A8-E44C-4781-9680-95CAC631CFB7}">
<File Id="manualimg" Name="manual.png" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\manual.png" />
</Component>
<Component Id="off" Guid="{702551D4-34DD-4B1B-B4F6-614DEFA4542A}">
<File Id="offimg" Name="off.png" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\off.png" />
</Component>
<Component Id="on" Guid="{7682A68D-712B-4F70-9EE2-FB4F0E04947D}">
<File Id="onimg" Name="on.png" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\on.png" />
</Component>
<Component Id="refresh" Guid="{9815CA13-659C-466D-B759-5EF557069D1B}">
<File Id="refreshimg" Name="refresh.png" KeyPath="yes" Source="$(var.WWU_UI.TargetDir)image\refresh.png" />
</Component>
</ComponentGroup>
</Fragment>
<Fragment>
<Icon Id="WWU_UI.exe" SourceFile="$(var.WWU_UI.TargetDir)WWU_UI.exe"/>
</Fragment>
</Wix>
You should nest the <Directory Id="ImageFolder"> under <Directory Id="INSTALLFOLDER">, like this:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="WWU">
<Directory Id="ImageFolder" Name="image"/>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder" Name="Programs">
<Directory Id="ProgramMenuDir" Name="WWU 1.0" />
</Directory>
<Directory Id="DesktopFolder" Name="Desktop" />
</Directory>
Note also that if there's no component in that folder, the empty directory won't be created. In order for this to happen, you'll have to author a component with <CreateFolder> element in it.
This is what you do.
Nest the subfolder underneath INSTALLFOLDER as stated by Yan.
Create the Feature Component with the CreateFolder bit inside
Example code:
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="WixInstallerExample" >
<Directory Id="test" Name="AnotherDirectory">
<Component Id="test" Guid="e29f1a9e-3ede-40d6-aba0-bfe451002ee3"
SharedDllRefCount="no" KeyPath="no" NeverOverwrite="no" Permanent="no" Transitive="no" Win64="no" Location="either">
<CreateFolder/>
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
<Feature Id="test" Title="testfolder" Level="1">
<ComponentRef Id="test"/>
</Feature>
</Fragment>

How to get parent node?

//* [ local-name()='component' and namespace-uri()='urn:hl7-org:v3' ]
Using thispath, I can get a node like this:
<?xml version="1.0" encoding="utf-8"?>
<ClinicalDocument xmlns="urn:hl7-org:v3">
<component>
<structuredBody>
<component>
<section>
<code code="10164-2" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC"/>
<title>History of Present Illness</title>
<text>
</text>
</section>
</component>
<component> ...... </component>
<component> ...... </component>
</structuredBody>
</component>
</ClinicalDocument>
In order to get the node as below:
<component>
<section>
<code code="10164-2" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC"/>
<title>History of Present Illness</title>
<text>
</text>
</section>
</component>
I change the path to :
//* [ local-name()='component' and namespace-uri()='urn:hl7-org:v3' and position()=1]
But, how can I get the same result by using [code="10164-2"] as a qualification?
edit 2012-12-17
//:component[1]//:component[.//:section/:code[#code='10164-2']]
this xpath works well and I can get the node I want . What should I do If I use
//*[local-name()='component' and namespace-uri()='urn:hl7-org:v3'])[1]
to select the parent <component/>node then add [#code='10164-2'] to the predicate part to get the <component/>child node i want. (I would like not to use : in the path to avoid namespace issue)
Use:
((//*[local-name()='component'
and namespace-uri()='urn:hl7-org:v3']
)[1]
//*[local-name()='component'
and
namespace-uri()='urn:hl7-org:v3'
]
)[1]
XSLT - based verification:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:copy-of select=
"((//*[local-name()='component'
and namespace-uri()='urn:hl7-org:v3']
)[1]
//*[local-name()='component'
and
namespace-uri()='urn:hl7-org:v3']
)[1]
"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<component xmlns="urn:hl7-org:v3">
<structuredBody>
<component>
<section>
<code code="10164-2" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC"/>
<title>History of Present Illness</title>
<text>
</text>
</section>
</component>
<component> ...... </component>
<component> ...... </component>
</structuredBody>
</component>
the XPath expression is evaluated and the results of this evaluation are copied to the output:
<component xmlns="urn:hl7-org:v3">
<section>
<code code="10164-2" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC"/>
<title>History of Present Illness</title>
<text/>
</section>
</component>
Just add and section/code/#code='10164-2' to your predicate:
//*:component[namespace-uri()='urn:hl7-org:v3' and section/code/#code='10164-2']
Note: You may have to remove namespace-uri()='urn:hl7-org:v3' if component isn't in that namespace. Your example in "in order to get the node as below:" does not have a namespace.
Also, I used *:component instead of local-name() since you tagged the question XPath 2.0.

Resources