Can I use hreflang tag in sitemap-index file? - sitemap

I have a sitemapindex file with sitemap and loc elements.
Can I add hreflang attribute to this file, is that logical? Because sitemapindex contains only URLs to other sitemaps.
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
<sitemap>
<loc>domain/en/sitemap-general.xml</loc>
</sitemap>
<sitemap>
<loc>domain/en/sitemap-categories.xml</loc>
</sitemap>
<sitemap>
<loc>domain/en/sitemap-brands.xml</loc>
</sitemap>
<sitemap>
<loc>domain/en/sitemap-products-1.xml</loc>
</sitemap>
<sitemap>
<loc>domain/en/sitemap-products-2.xml</loc>
</sitemap>
<sitemap>
<loc>
domain/en/sitemap-products-images-1.xml
</loc>
</sitemap>
<sitemap>
<loc>
domain/en/sitemap-products-images-2.xml
</loc>
</sitemap>
</sitemapindex>

Related

Create application/atom+xml result

I have an API on GoogleCloud and need to define an endpoint which returns a feed usable in Excel PowerPivot and Power BI. I have found this library using feed.ToAtom(), but the created feed does not work in PoverPivot, I get the following error: The payload kind 'Value' of the given data feed is not supported. but I can't find any information.
How can I create the needed result?
Here a snipped of the current result:
<?xml version="1.0" encoding="UTF-8"?>
<feed
xmlns="http://www.w3.org/2005/Atom">
<title>dfhfdhsfdh.net blog</title>
<id>http://dfhfdhsfdh.net/blojhlkjluizg</id>
<updated>2022-05-19T07:51:07+02:00</updated>
<rights>sdfsdf</rights>
<subtitle>discussion about tech, footie, photos</subtitle>
<link href="http://dfhfdhsfdh.net/blojhlkjluizg"></link>
<author>
<name>ergsrdg sdfgsfdg</name>
<email>dfhfdhsfdh#dfhfdhsfdh.net</email>
</author>
<entry>
<title>22906201</title>
<updated>2022-05-19T07:51:07+02:00</updated>
<id>http://dfhfdhsfdh.net/sdfsdfblog</id>
<link href="http://dfhfdhsfdh.net/blfghjghjog" rel="alternate"></link>
<summary type="html"></summary>
</entry>
<entry>
<title>22906197</title>
<updated>2022-05-19T07:51:07+02:00</updated>
<id>http://dfhfdhsfdh.net/sdfsdfblog</id>
<link href="http://dfhfdhsfdh.net/blfghjghjog" rel="alternate"></link>
<summary type="html"></summary>
</entry>
</feed>
I have also created the result by my self, the result is the following, but still get that error:
<?xml version="1.0" encoding="UTF-8"?>
<feed
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns="http://www.w3.org/2005/Atom">
<title type="text">Guest Requests</title>
<id>http://localhost:4444/requests/GuestRequests/</id>
<updated>2022-05-19T09:33:40+02:00</updated>
<entry>
<id>http://localhost:4444/requests/22906201</id>
<title type="text">22906201</title>
<updated>2022-05-19T09:33:40+02:00</updated>
<author>
<name>TODO</name>
</author>
<content type="application/xml">
<m:properties>
<d:id>22906201</d:id>
<d:title>22906201</d:title>
</m:properties>
</content>
</entry>
</feed>

Orbeon static autocomplete not working as expected

I'm using Orbeon v2017.1 and I'd like to add an autocomplete field with a static itemset.
I've tried implementing it as it is defined here
https://doc.orbeon.com/form-runner/component/autocomplete#static
and I've also tried creating a service and action which will fill the data, but it displays it as radio buttons instead of populating the dropdown.
Is there a working example for this version of Orbeon which I could look at?
EDIT:
Here is an example of two autocomplete fields (dynamic and static)
I'm not sure if the used free web service supports filtering, so the fr-search-value was not used for the dynamic one (is it possible to filter it somehow in Orbeon for both static and dynamic?)
<xh:html xmlns:xh="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:exf="http://www.exforms.org/exf/1-0"
xmlns:fb="http://orbeon.org/oxf/xml/form-builder"
xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
xmlns:saxon="http://saxon.sf.net/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:sql="http://orbeon.org/oxf/xml/sql"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xxf="http://orbeon.org/oxf/xml/xforms"
xmlns:xxi="http://orbeon.org/oxf/xml/xinclude">
<xh:head>
<xh:title/>
<xf:model id="fr-form-model" xxf:expose-xpath-types="true">
<xf:instance id="all-countries"
src="http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso/ListOfCountryNamesByName/XML"/>
<!-- Main instance -->
<xf:instance id="fr-form-instance" xxf:exclude-result-prefixes="#all" xxf:index="id">
<form>
<section-1>
<country-dynamic-autocomplete label=""/>
<country-static-autocomplete label=""/>
</section-1>
</form>
</xf:instance>
<!-- Bindings -->
<xf:bind id="fr-form-binds" ref="instance('fr-form-instance')">
<xf:bind id="section-1-bind" name="section-1" ref="section-1">
<xf:bind id="country-dynamic-autocomplete-bind" ref="country-dynamic-autocomplete"
name="country-dynamic-autocomplete"/>
<xf:bind id="country-static-autocomplete-bind" ref="country-static-autocomplete"
name="country-static-autocomplete"/>
</xf:bind>
</xf:bind>
<!-- Metadata -->
<xf:instance xxf:readonly="true" id="fr-form-metadata" xxf:exclude-result-prefixes="#all">
<metadata>
<application-name>insurance</application-name>
<form-name>test</form-name>
<title xml:lang="en"/>
<description xml:lang="en"/>
</metadata>
</xf:instance>
<!-- Attachments -->
<xf:instance id="fr-form-attachments" xxf:exclude-result-prefixes="#all">
<attachments>
<css mediatype="text/css" filename="" size=""/>
<pdf mediatype="application/pdf" filename="" size=""/>
</attachments>
</xf:instance>
<!-- All form resources -->
<!-- Don't make readonly by default in case a service modifies the resources -->
<xf:instance id="fr-form-resources" xxf:readonly="false" xxf:exclude-result-prefixes="#all">
<resources>
<resource xml:lang="en">
<country-dynamic-autocomplete>
<label>Countries Dynamic Autocomplete</label>
<hint/>
</country-dynamic-autocomplete>
<country-static-autocomplete>
<label>Countries Static Autocomplete</label>
<hint/>
</country-static-autocomplete>
<section-1>
<label>Country Section</label>
</section-1>
</resource>
</resources>
</xf:instance>
</xf:model>
</xh:head>
<xh:body>
<fr:view>
<fr:body xmlns:xbl="http://www.w3.org/ns/xbl" xmlns:p="http://www.orbeon.com/oxf/pipeline"
xmlns:oxf="http://www.orbeon.com/oxf/processors">
<fr:section id="section-1-control" bind="section-1-bind">
<xf:label ref="$form-resources/section-1/label"/>
<fr:grid>
<xh:tr>
<xh:td>
<fr:autocomplete xmlns:xxbl="http://orbeon.org/oxf/xml/xbl"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
id="country-dynamic-autocomplete-control"
labelref="#label"
max-results-displayed="300"
resource="http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso/ListOfCountryNamesByName/XML"
bind="country-dynamic-autocomplete-bind">
<xf:label ref="$form-resources/country-dynamic-autocomplete/label"/>
<xf:hint ref="$form-resources/country-dynamic-autocomplete/hint"/>
<xf:alert ref="$fr-resources/detail/labels/alert"/>
<xf:itemset ref="/ArrayOftCountryCodeAndName/tCountryCodeAndName">
<xf:label ref="sName"/>
<xf:value ref="sISOCode"/>
</xf:itemset>
</fr:autocomplete>
</xh:td>
</xh:tr>
<xh:tr>
<xh:td>
<fr:autocomplete id="country-static-autocomplete-control" ref="country-static-autocomplete"
dynamic-itemset="false"
bind="country-static-autocomplete-bind">
<xf:label ref="$form-resources/country-static-autocomplete/label"/>
<xf:hint ref="$form-resources/country-static-autocomplete/hint"/>
<xf:alert ref="$fr-resources/detail/labels/alert"/>
<xf:itemset ref="instance('all-countries')/ArrayOftCountryCodeAndName/tCountryCodeAndName">
<xf:label ref="sName"/>
<xf:value ref="sISOCode"/>
</xf:itemset>
</fr:autocomplete>
</xh:td>
</xh:tr>
</fr:grid>
</fr:section>
</fr:body>
</fr:view>
</xh:body>
</xh:html>

xslt sorting for some part of a file

I'm very new to XSLT, and I want to sort a part of XML file.(keeping all the file data)
Here's the file :
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test.xsd">
<SchemaVersion>1.0</SchemaVersion>
<Header>### uVision Project, (C) Keil Software</Header>
<Extensions>
<cExt>*.c</cExt>
<aExt>*.s*; *.src; *.a*</aExt>
<oExt>*.obj</oExt>
<lExt>*.lib</lExt>
<tExt>*.txt; *.h; *.inc</tExt>
<pExt>*.plm</pExt>
<CppX>*.cpp</CppX>
<nMigrate>0</nMigrate>
</Extensions>
<DateTime>
<dwLowDateTime>0</dwLowDateTime>
<dwHighDateTime>0</dwHighDateTime>
</DateTime>
<Target>
<TargetName>LYNX_XERIUS_APRR_CPU2006_0091</TargetName>
<ToolsetNumber>0x4</ToolsetNumber>
<TargetOption>
<OPTTT>
<gFlags>0</gFlags>
</OPTTT>
<AAA>
<SetRegEntry>
<Number>0</Number>
</SetRegEntry>
</AAA>
<Breakpoint>
<Bp>
<Number>0</Number>
</Bp>
<Bp>
<Number>1</Number>
</Bp>
<Bp>
<Number>2</Number>
</Bp>
<Bp>
<Number>3</Number>
</Bp>
<Bp>
<Number>4</Number>
</Bp>
</Breakpoint>
<Tracepoint>
<THDelay>0</THDelay>
</Tracepoint>
<DebugFlag>
<trace>0</trace>
</DebugFlag>
<LintExecutable></LintExecutable>
</TargetOption>
</Target>
<Target>
<TargetName>Debug</TargetName>
<ToolsetNumber>0x4</ToolsetNumber>
<TargetOption>
<OPTTT>
<gFlags>0</gFlags>
</OPTTT>
<AAA>
<SetRegEntry>
<Number>0</Number>
</SetRegEntry>
</AAA>
<Breakpoint>
<Bp>
<Number>0</Number>
</Bp>
<Bp>
<Number>1</Number>
</Bp>
<Bp>
<Number>2</Number>
</Bp>
<Bp>
<Number>3</Number>
</Bp>
<Bp>
<Number>4</Number>
</Bp>
</Breakpoint>
<Tracepoint>
<THDelay>0</THDelay>
</Tracepoint>
<DebugFlag>
<trace>0</trace>
</DebugFlag>
<LintExecutable></LintExecutable>
</TargetOption>
</Target>
<Target>
<TargetName>LYNX_HERMES_APRR_SERIE_200</TargetName>
<ToolsetNumber>0x4</ToolsetNumber>
<TargetOption>
<OPTTT>
<gFlags>0</gFlags>
</OPTTT>
<AAA>
<SetRegEntry>
<Number>0</Number>
</SetRegEntry>
</AAA>
<Breakpoint>
<Bp>
<Number>0</Number>
</Bp>
<Bp>
<Number>1</Number>
</Bp>
<Bp>
<Number>2</Number>
</Bp>
<Bp>
<Number>3</Number>
</Bp>
<Bp>
<Number>4</Number>
</Bp>
</Breakpoint>
<Tracepoint>
<THDelay>0</THDelay>
</Tracepoint>
<DebugFlag>
<trace>0</trace>
</DebugFlag>
<LintExecutable></LintExecutable>
</TargetOption>
</Target>
<Group>
<GroupName>::CMSIS</GroupName>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel>
<RteFlg>1</RteFlg>
</Group>
</Project>
Here's my XSLT :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns="urn:TestNamespace" >
<xsl:output indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="text()[not(string-length(normalize-space()))]"/>
<xsl:template match="Project">
<xsl:copy>
<xsl:apply-templates select="Target">
<xsl:sort select="TargetName"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<!-- global template to copy everything that doesn't match the other templates -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I got a XML file sorted by TargetName as output, but with only Target nodes....
How can I setup the select case to keep the unfiltered nodes ?
I also tested with :
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates select="Target">
<xsl:sort select="TargetName"/>
</xsl:apply-templates>
</xsl:copy>
In this case, all data is kept but there is no sorting ?
I will appreciate some explanation to improve my knowledge.
Best Regards
One approach is:
<xsl:template match="Project">
<xsl:copy>
<xsl:apply-templates select="node()">
<xsl:sort select="TargetName" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
Why is your solution not working:
<xsl:apply-templates select="Target">
You select only Target to apply further.
I would probably do this (using XSLT 2.0):
<xsl:template match="Project">
<xsl:copy>
<xsl:for-each-group select="*" group-adjacent="node-name()">
<xsl:apply-templates>
<xsl:sort select="TargetName"/>
</xsl:apply-templates>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
on the assumption that sorting groups of elements other than Target elements does no harm. But it would probably be cleaner to have a conditional (xsl:choose) inside the xsl:for-each-group so the sorting is only done when test="self::Target".

XSLT - how can I filter data source by data from external XML?

I have the following XML data structure:
<root>
<info>
<creationDate>2015-03-11 11:45:49</creationDate>
</info>
<promotions>
<promotion>
<header>
<id>1</id>
<name>Name 1</name>
</header>
<positions>
<position>
<id>1</id>
<name>Some position name 1</name>
</position>
<position>
<id>2</id>
<name>Some position name 2</name>
</position>
</position>
</positions>
</promotion>
<promotion>
<header>
<id>2</id>
<name>Name 2</name>
</header>
<positions>
<position>
<id>3</id>
<name>Some position name 3</name>
</position>
</positions>
</promotion>
</promotions>
</root>
Which is used as primary data source for my template like this:
<xsl:template match="root">
...
I need to filter the above by "filter.xml" file, containing promotion Id's to filter out, and it needs to work on IE7 . Is something like this possible?
For starters I tried to find a way to add filter in xsl:apply-templates select statement, so that only promotion with Id=2 will be processed by template but failed - is it possible to write Xpath that will say:
"Give me everything from root node but promotions only with Id = 2" ?
Thanks.
EDIT1:
Sorry about the namespace - it shouldn't be there in the first place. As for the filter.xml - it is not clearly defined yet - for now, I'm using the following:
<usedUpPromotions>
<header>
<promotionId>
1
</promotionId>
</header>
<header>
<promotionId>
2
</promotionId>
</header>
<header>
<promotionId>
3
</promotionId>
</header>
</usedUpPromotions>
I think of using something like:
<xsl:apply-templates select="root[hereIsMyWhereId != (document('Load externalXmlHere')/select/IdtoFilterOut)"/>
But I can't seem to find a way to filter out data that way...
EDIT2:
I'll try to explain using code as example - let's assume for a moment that we have the following:
XmlData initialXmlData; <- this is our XML data before filtering
XmlData filter; -< this contains the filter.xml data
Html GenerateHtmlFromTemplate(XmlData initialXmlData) - this is my Xslt template
{
...some precessing here
}
I would like to modify my template to achieve the following:
Html GenerateHtmlFromTemplate(XmlData initialXmlData, XmlData filter)
{
XmlData filteredData = data.FilterBy(filter);
...same processing here as above, but use 'filteredData', instead of 'initialXmlData'
}
I hope it's more clear now :) - the main problem, it would seem is that the Id element, I want to filter by, is inside array variable, so I cannot simply use:
in my primary template - instead I bypassed the problem, by filtering on for-each loop later on but I would still like to know if it is possible to simply tell the template "from now on use filtered data, instead of original".
Edit3:
#michael.hor257k - to answer your question, I have modified templates you provided:
Template.xml:
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="#"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ksx="http://www.test.com/test" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<xsl:output encoding="utf-8" indent="no" method="html"/>
<root xmlns="http://www.test.com/test">
<info>
<creationDate>2015-03-11 11:45:49</creationDate>
</info>
<promotions>
<promotion>
<header>
<id atr="tre">1</id>
<name>Promotion 1</name>
</header>
<positions>
<position>
<id>1</id>
<name>Position 1a</name>
</position>
<position>
<id>2</id>
<name>Position 1b</name>
</position>
</positions>
</promotion>
<promotion>
<header>
<id>2</id>
<name>Promotion 2</name>
</header>
<positions>
<position>
<id>3</id>
<name>Position 2a</name>
</position>
</positions>
</promotion>
</promotions>
</root>
<xsl:param name="new-path" select="'new.xml'"/>
<xsl:variable name="new-promotions" select="document($new-path)/newPromotions/promotion" />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ksx:root">
<xsl:copy>
<xsl:apply-templates select="ksx:promotions/ksx:promotion[not(ksx:header/ksx:id=$new-promotions/header/id)]"/>
<xsl:apply-templates select="$new-promotions"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
new.xml:
<?xml version="1.0" encoding="utf-8"?>
<newPromotions>
<promotion>
<header>
<id>2</id>
<name>New Promotion 2</name>
</header>
<positions>
<position>
<id>4</id>
<name>New Position 2A</name>
</position>
</positions>
</promotion>
<promotion>
<header>
<id>3</id>
<name>New Promotion 3</name>
</header>
<positions>
<position>
<id>5</id>
<name>New Position 3A</name>
</position>
</positions>
</promotion>
</newPromotions>
If you save those, and open template.xml in Chrome it will work nicely - what I wanted however was to filter out data outside template node:
<xsl:template match="ksx:root">
So, I tried this:
<xsl:template match="ksx:root[ksx:promotion/ksx:header/ksx:id=1]">
And I expected to get all data from root but with promotions filtered to those with Id = 1 - but it gave all data and no errors, now I noticed that this:
<xsl:template match="ksx:root[ksx:promotions/ksx:promotion/ksx:header/ksx:id=$new-promotions/header/id]">
causes an error "Variables cannot be used within this expression" - so I guess, what I want to do is probably impossible from outside the template node...?
Sorry for the confusion - I hope now it is more clear. I simply wanted to treat template node as a method and "pass" filtered data to it, instead of filtering the data inside of it.
Edit4:
In my specific case, I have large "root" dataset of promotions, and small, external XML file that contains promotion Id's to hide during processing. So in my case filtering would mean: "Take everything from root element, but filter promotions so only those which Ids are NOT in the external file, will be processed". So if I have:
<root xmlns="http://www.test.com/test">
<info>
<creationDate>2015-03-11 11:45:49</creationDate>
</info>
<someData1>Some data 1</someData1>
<someData2>Some data 2</someData2>
<someData3>Some data 3</someData3>
<promotions>
<promotion>
<header>
<id>1</id>
<name>Promotion 1</name>
</header>
<positions>
<position>
<id>1</id>
<name>Position 1a</name>
</position>
<position>
<id>2</id>
<name>Position 1b</name>
</position>
</positions>
</promotion>
<promotion>
<header>
<id>2</id>
<name>Promotion 2</name>
</header>
<positions>
<position>
<id>3</id>
<name>Position 2a</name>
</position>
</positions>
</promotion>
<promotion>
<header>
<id>3</id>
<name>Promotion 3</name>
</header>
<positions>
<position>
<id>4</id>
<name>Position 3a</name>
</position>
</positions>
</promotion>
</promotions>
</root>
And filter by:
<?xml version="1.0" encoding="UTF-8"?>
<usedUpPromotions>
<id>1</id>
<id>2</id>
</usedUpPromotions>
Then I would expect to get:
<root xmlns="http://www.test.com/test">
<info>
<creationDate>2015-03-11 11:45:49</creationDate>
</info>
<someData1>Some data 1</someData1>
<someData2>Some data 2</someData2>
<someData3>Some data 3</someData3>
<promotions>
<promotion>
<header>
<id>3</id>
<name>Promotion 3</name>
</header>
<positions>
<position>
<id>4</id>
<name>Position 3a</name>
</position>
</positions>
</promotion>
</promotions>
</root>
To process only promotions with Id=2, you can use (from the context of root):
<xsl:apply-templates select="promotions/promotion[header/id='2']"/>
Added:
Here's an example showing how you can "merge" your input XML with an overriding XML document. Given:
XML
<root>
<info>
<creationDate>2015-03-11 11:45:49</creationDate>
</info>
<promotions>
<promotion>
<header>
<id>1</id>
<name>Promotion 1</name>
</header>
<positions>
<position>
<id>1</id>
<name>Position 1a</name>
</position>
<position>
<id>2</id>
<name>Position 1b</name>
</position>
</positions>
</promotion>
<promotion>
<header>
<id>2</id>
<name>Promotion 2</name>
</header>
<positions>
<position>
<id>3</id>
<name>Position 2a</name>
</position>
</positions>
</promotion>
</promotions>
</root>
new.xml
<newPromotions>
<promotion>
<header>
<id>2</id>
<name>New Promotion 2</name>
</header>
<positions>
<position>
<id>4</id>
<name>New Position 2A</name>
</position>
</positions>
</promotion>
<promotion>
<header>
<id>3</id>
<name>New Promotion 3</name>
</header>
<positions>
<position>
<id>5</id>
<name>New Position 3A</name>
</position>
</positions>
</promotion>
</newPromotions>
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="new-path" select="'path/to/new.xml'"/>
<xsl:variable name="new-promotions" select="document($new-path)/newPromotions/promotion" />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="promotions">
<xsl:copy>
<xsl:apply-templates select="promotion[not(header/id=$new-promotions/header/id)]"/>
<xsl:apply-templates select="$new-promotions"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<root>
<info>
<creationDate>2015-03-11 11:45:49</creationDate>
</info>
<promotions>
<promotion>
<header>
<id>1</id>
<name>Promotion 1</name>
</header>
<positions>
<position>
<id>1</id>
<name>Position 1a</name>
</position>
<position>
<id>2</id>
<name>Position 1b</name>
</position>
</positions>
</promotion>
<promotion>
<header>
<id>2</id>
<name>New Promotion 2</name>
</header>
<positions>
<position>
<id>4</id>
<name>New Position 2A</name>
</position>
</positions>
</promotion>
<promotion>
<header>
<id>3</id>
<name>New Promotion 3</name>
</header>
<positions>
<position>
<id>5</id>
<name>New Position 3A</name>
</position>
</positions>
</promotion>
</promotions>
</root>
In response to your edit #4:
So in my case filtering would mean: "Take everything from root
element, but filter promotions so only those which Ids are NOT in the
external file, will be processed".
My answer above does two things:
It copies everything from the input XML document except promotions whose IDs are in the external file;
It adds all the promotions listed in the external file.
If you only want to do #1 but not #2, then change this:
<xsl:template match="promotions">
<xsl:copy>
<xsl:apply-templates select="promotion[not(header/id=$new-promotions/header/id)]"/>
<xsl:apply-templates select="$new-promotions"/>
</xsl:copy>
</xsl:template>
to:
<xsl:template match="promotions">
<xsl:copy>
<xsl:apply-templates select="promotion[not(header/id=$new-promotions/header/id)]"/>
</xsl:copy>
</xsl:template>
In the given example, the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<info>
<creationDate>2015-03-11 11:45:49</creationDate>
</info>
<promotions>
<promotion>
<header>
<id>1</id>
<name>Promotion 1</name>
</header>
<positions>
<position>
<id>1</id>
<name>Position 1a</name>
</position>
<position>
<id>2</id>
<name>Position 1b</name>
</position>
</positions>
</promotion>
</promotions>
</root>

How to remove most namespaces from input XML in XSLT (nokogiri example)

I have this piece of nokogiri code, thats runs slower then I like on large input. How would you redo this in XSLT? Any other ideas to make it run faster?
# remove namespaces (other then soapenv) from input xml, and move
# them to type attribute.
# xml is Nokogiri::XML object
def cleanup_namespaces(xml)
protected_ns = %w( soapenv )
xml.traverse do |el|
next unless el.respond_to? :namespace
if (ns=el.namespace) &&
!protected_ns.include?(ns.prefix) then
el['type'] = "#{ns.prefix}:#{el.name}"
el.namespace = nil
end
end
xml
end
The sample input I am testing with is:
<?xml version="1.0"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns1:getAccountDTOResponse xmlns:ns1="http://www.example.com/pw/services/PWServices"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<getAccountDTOReturn xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns2="urn:PWServices"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns2:Account">
<ns1:ID soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="xsd:long">0</ns1:ID>
<ns1:accountNumber xsi:type="soapenc:string" />
<ns1:accountType xsi:type="soapenc:string" />
<ns1:clientData xsi:type="soapenc:Array" xsi:nil="true" />
<ns1:name xsi:type="soapenc:string" />
<ns1:parentRef xsi:type="soapenc:string" />
</getAccountDTOReturn>
</ns1:getAccountDTOResponse>
</soapenv:Body>
</soapenv:Envelope>
The expected output is:
<?xml version="1.0"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<getAccountDTOResponse xmlns:ns1="http://www.example.com/pw/services/PWServices"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
type="ns1:getAccountDTOResponse">
<getAccountDTOReturn xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns2="urn:PWServices"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns2:Account">
<ID soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="xsd:long" type="ns1:ID">0</ID>
<accountNumber xsi:type="soapenc:string"
type="ns1:accountNumber" />
<accountType xsi:type="soapenc:string"
type="ns1:accountType" />
<clientData xsi:type="soapenc:Array" xsi:nil="true"
type="ns1:clientData" />
<name xsi:type="soapenc:string" type="ns1:name" />
<parentRef xsi:type="soapenc:string"
type="ns1:parentRef" />
</getAccountDTOReturn>
</getAccountDTOResponse>
</soapenv:Body>
</soapenv:Envelope>
This input is a SOAP response. A tangential question is, what is the
point of the ns1 type namespace in the SOAP response, and is it
reasonable to throw them away completely. I don't seem to need to
reference them when parsing the response.
This XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[namespace-uri() =
'http://www.example.com/pw/services/PWServices']">
<xsl:element name="{local-name()}">
<xsl:attribute name="type">
<xsl:value-of select="name()"/>
</xsl:attribute>
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Against your sample will produce this result:
<?xml version="1.0" encoding="UTF-16"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<getAccountDTOResponse type="ns1:getAccountDTOResponse" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<getAccountDTOReturn soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns2:Account" xmlns:ns1="http://www.example.com/pw/services/PWServices" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="urn:PWServices">
<ID type="ns1:ID" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:long">0</ID>
<accountNumber type="ns1:accountNumber" xsi:type="soapenc:string"></accountNumber>
<accountType type="ns1:accountType" xsi:type="soapenc:string"></accountType>
<clientData type="ns1:clientData" xsi:type="soapenc:Array" xsi:nil="true"></clientData>
<name type="ns1:name" xsi:type="soapenc:string"></name>
<parentRef type="ns1:parentRef" xsi:type="soapenc:string"></parentRef>
</getAccountDTOReturn>
</getAccountDTOResponse>
</soapenv:Body>
</soapenv:Envelope>

Resources