I've got a problem with xsl:include and default namespaces which is causing the final xml document contain nodes with the xmlns=""
In this synario I have 1 source document which is Plain Old XML and doesn't have a namespace:
<?xml version="1.0" encoding="UTF-8"?>
<SourceDoc>
<Description>Hello I'm the source description</Description>
<Description>Hello I'm the source description 2</Description>
<Description/>
<Title>Hello I'm the title</Title>
</SourceDoc>
This document is transformed into 2 different xml documents each with their own default namespace.
First Document:
<?xml version="1.0" encoding="utf-8"?>
<OutputDocType1 xmlns="http://MadeupNS1">
<Description >Hello I'm the source description</Description>
<Description>Hello I'm the source description 2</Description>
<Title>Hello I'm the title</Title>
</OutputDocType1>
Second Document:
<?xml version="1.0" encoding="utf-8"?>
<OutputDocType2 xmlns="http://MadeupNS2">
<Description>Hello I'm the source description</Description>
<Description>Hello I'm the source description 2</Description>
<DocTitle>Hello I'm the title</DocTitle>
</OutputDocType2>
I want to be able to re-use the template for descriptions in both of the transforms. As it's the same logic for both types of document. To do this I created a template file which was xsl:included in the other 2 transformations:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml"/>
<xsl:template match="Description[. != '']">
<Description>
<xsl:value-of select="."/>
</Description>
</xsl:template>
</xsl:stylesheet>
Now the problem here is that this shared transformation can't have a default Namespace as it will be different depending on which of the calling transformations calls it.
E.g. for First Document Transformation:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml"/>
<xsl:template match="SourceDoc">
<OutputDocType1 xmlns="http://MadeupNS1">
<xsl:apply-templates select="Description"/>
<xsl:if test="Title">
<Title>
<xsl:value-of select="Title"/>
</Title>
</xsl:if>
</OutputDocType1>
</xsl:template>
<xsl:include href="Template.xsl"/>
</xsl:stylesheet>
This actually outputs it as follows:
<?xml version="1.0" encoding="utf-8"?>
<OutputDocType1 xmlns="http://MadeupNS1">
<Description xmlns="">Hello I'm the source description</Description>
<Description xmlns="">Hello I'm the source description 2</Description>
<Title>Hello I'm the title</Title>
</OutputDocType1>
Here is the problem. On the description Lines I get an xmlns=""
Does anyone know how to solve this issue?
Thanks
Dave
Your first xslt, which contains the literal result element Description has no default namespace. This element is therefore in no namespace, and is being explicitly rendered as such via xmlns="".
Section 6.2 of Namespaces in XML 1.0 says that:
The attribute value in a default
namespace declaration MAY be empty.
This has the same effect, within the
scope of the declaration, of there
being no default namespace.
In order to control the namespace generated in the included stylesheet you will need to pass the namespace-uri through to its templates, using a variable or param.
<!-- in the included stylesheet -->
<xsl:template match="Description[. != '']">
<xsl:element name="Description" namespace="{$output-namespace}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<!--
and add this to your First Document Transformation stylesheet
as a top level element under xsl:stylesheet
-->
<xsl:variable name="output-namespace" select="'http://MadeupNS1'"/>
Related
I have requirement where I have to add Namespace and xsi to the
element from the source xml with No Namespace.
In Source XML I am just getting the Nodes and there is No namespace
and another program needs BizTalk to add Namespace and XSI to the XML for its processing.
I tried:
Used add namespace pipeline component. (It just added
namespace and not the xsi bits)
Used Map for putting up the desired format and yes no luck as got
just the namespace.
Need your help around this.
My source XML is like
<?xml version="1.0" encoding="UTF-16"?>
<Document>
<CstmrPmtStsRpt>
<GrpHdr>
<MsgId></MsgId>
<CreDtTm></CreDtTm>
<InitgPty>
<Id>
<OrgId>
<BICOrBEI></BICOrBEI>
</OrgId>
</Id>
</InitgPty>
</GrpHdr>
<OrgnlGrpInfAndSts>
<OrgnlMsgId></OrgnlMsgId>
<OrgnlMsgNmId></OrgnlMsgNmId>
<OrgnlNbOfTxs></OrgnlNbOfTxs>
<OrgnlCtrlSum></OrgnlCtrlSum>
<GrpSts>ACCP</GrpSts>
</OrgnlGrpInfAndSts>
</CstmrPmtStsRpt>
</Document>
My Required format is as below:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="MyNamespace">
<CstmrPmtStsRpt>
<GrpHdr>
<MsgId></MsgId>
<CreDtTm></CreDtTm>
<InitgPty>
<Id>
<OrgId>
<BICOrBEI></BICOrBEI>
</OrgId>
</Id>
</InitgPty>
</GrpHdr>
<OrgnlGrpInfAndSts>
<OrgnlMsgId></OrgnlMsgId>
<OrgnlMsgNmId></OrgnlMsgNmId>
<OrgnlNbOfTxs></OrgnlNbOfTxs>
<OrgnlCtrlSum></OrgnlCtrlSum>
<GrpSts>ACCP</GrpSts>
</OrgnlGrpInfAndSts>
</CstmrPmtStsRpt>
</Document>
Use the namespace attribute of xsl:element like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*">
<xsl:element name="{local-name()}" namespace="MyNamespace">
<xsl:namespace name="xsi" select="'http://www.w3.org/2001/XMLSchema-instance'"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Edit: Since you need to work with XSLT-1.0. Use following stylesheet:
<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/Document">
<Document xmlns="MyNamespace"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:apply-templates/>
</Document>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}" namespace="MyNamespace">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Note, that you need to know your rootnode's name for this (in this case Document).
BizTalk Answer:
First, it's a good thing the incoming document has no namespace. Xml Namespaces are far, far, far more trouble than they're worth and should be avoided/removed whenever possible.
Second the output format is not valid Xml. "MyNamespace" is not a valid URI and can't be used for a Namespace. If this is what they are asking for, they need to fix that first.
But, if you must, your process should not be "add a namespace". What you're really doing is Transforming from SysA's Document to SysB's Document. For that, use a Map. You will use to practially identical Schemas, one with and one without the Target Namespace.
The Mapper will handle xsi for you as well, if it's needed.
i have the following xml and xslt to render it, but got no results. I checked again and again and see not path problem, and the xsl went through the compiler. so I am not sure if it's namespace problem or something else. many thx!
XML file
<?xml version="1.0" encoding="UTF-8"?>
<bibdataset xsi:schemaLocation="http://www.elsevier.com/xml/ani/ani http://www.elsevier.com/xml/ani/embase_com.xsd"
xmlns="http://www.elsevier.com/xml/ani/ani"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ce="http://www.elsevier.com/xml/ani/common"
xmlns:ait="http://www.elsevier.com/xml/ani/ait">
<item>
<bibrecord>
<item-info>
<itemidlist><ce:doi>10.1258/0268355042555000</ce:doi>
</itemidlist>
</item-info>
<head>
<citation-title>
<titletext xml:lang="en" original="y">Effect of seasonal variations on the emergence of deep venous thrombosis of the lower extremity
</titletext>
</citation-title>
<abstracts>
<abstract xml:lang="en" original="y">
<ce:para>Objective: We aimed to determine the role of seasonal and meteorological variations in the incidence of lower extremity
</ce:para>
</abstract>
</abstracts>
</head>
</bibrecord>
</item>
</bibdataset>
XSLT file
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.elsevier.com/xml/ani/ani"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ce="http://www.elsevier.com/xml/ani/common"
xmlns:ait="http://www.elsevier.com/xml/ani/ait">
<xsl:output indent="yes" omit-xml-declaration="no"
media-type="application/xml" encoding="UTF-8" />
<xsl:template match="/">
<searchresult>
<xsl:apply-templates
select="/bibdataset/item/bibrecord" />
</searchresult>
</xsl:template>
<xsl:template match="bibrecord">
<document>
<title><xsl:value-of select="head/citation-title/titletext" /></title>
<snippet>
<xsl:value-of select="head/abstracts/abstract/ce:para" />
</snippet>
<url>
<xsl:variable name="doilink" select="item-info/itemidlist/ce:doi"/>
<xsl:value-of
select="concat('http://dx.doi.org/', $doilink)" />
</url>
</document>
</xsl:template>
</xsl:stylesheet>
This is indeed an issue with namespaces. In your XML, you have declared a default namespace meaning the root element, and all its descendants, and in this namespace.
<bibdataset .xmlns="http://www.elsevier.com/xml/ani/ani" ...
Now, in your XSLT, you have also declared this namespace, but without a prefix.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.elsevier.com/xml/ani/ani"
This means it only applies to the elements you are outputting, so your searchresult element gets output in this namespace
<searchresult xmlns="http://www.elsevier.com/xml/ani/ani"
However, it doesn't apply to the xpath expression in your XSLT, and so these are looking for elements in your input XML with no namespace.
In XSLT 2.0 the solution would be to simply declare an "xpath-default-namespace"
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.elsevier.com/xml/ani/ani"
xpath-default-namespace="http://www.elsevier.com/xml/ani/ani" ...
In XSLT 1.0, you will have to declare the namespace with a prefix, and use this prefix in all the xpath expressions.
Try this XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.elsevier.com/xml/ani/ani"
xmlns:ani="http://www.elsevier.com/xml/ani/ani"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ce="http://www.elsevier.com/xml/ani/common"
xmlns:ait="http://www.elsevier.com/xml/ani/ait"
exclude-result-prefixes="ani">
<xsl:output indent="yes" omit-xml-declaration="no"
media-type="application/xml" encoding="UTF-8" />
<xsl:template match="/">
<searchresult>
<xsl:apply-templates
select="/ani:bibdataset/ani:item/ani:bibrecord" />
</searchresult>
</xsl:template>
<xsl:template match="ani:bibrecord">
<document>
<title><xsl:value-of select="ani:head/ani:citation-title/ani:titletext" /></title>
<snippet>
<xsl:value-of select="ani:head/ani:abstracts/ani:abstract/ce:para" />
</snippet>
<url>
<xsl:variable name="doilink" select="ani:item-info/ani:itemidlist/ce:doi"/>
<xsl:value-of
select="concat('http://dx.doi.org/', $doilink)" />
</url>
</document>
</xsl:template>
</xsl:stylesheet>
Note that you can remove the line xmlns="http://www.elsevier.com/xml/ani/ani" but that would mean your searchresult (and other) elements would be output with no namespace, so you would need to output it as <ani:searchresult> if you wanted it in the given namespace.
I have to make an xsl for an xml output exported from a database. The name tags in xml have a prefix bib followed by a colon (as in bib:), and it was defined in xml. But I still got an xsl compiler error saying bib: is not declared. So I added the declaration in xsl. this time the error went away, but the result comes out zero, and I checked the path that is correct. I also tried to exclude "bib:" prefix in xsl after declaration but got the same zero result. I am new to xsl so I don't know what is wrong here. These are my files. Thanks very much.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<embasexmllist>
<cards items="1">
<bib:card items="0" xmlns:bib="http://elsevier.co.uk/namespaces/2001/bibliotek">-
<bib:cardfields>
<bib:Fulltext>
<bib:DOI>10.1371/journal.pone.0068303</bib:DOI>
</bib:Fulltext>
<bib:Title>Mesothelin Virus-Like Particle Immunization Controls Pancreatic Cancer Growth through CD8+ T Cell Induction and Reduction in the Frequency of CD4+foxp3+ICOS- Regulatory T Cells
</bib:Title>
</bib:cardfields>
</bib:card>
</cards>
</embasexmllist>
XSL
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:bib="http://www.bib.com/xml">
<xsl:output indent="yes" omit-xml-declaration="no"
media-type="application/xml" encoding="UTF-8" />
<xsl:template match="/">
<searchresult>
<xsl:apply-templates
select="/embasexmllist/cards/bib:card/bib:cardfields" />
</searchresult>
</xsl:template>
<xsl:template match="bib:cardfields">
<document>
<title><xsl:value-of select="bib:Title" /></title>
<snippet>
<xsl:value-of select="bib:Title" />
</snippet>
<url>
<xsl:variable name="doi" select="bib:Fulltext/bib:DOI"/>
<xsl:value-of
select="concat('http://dx.doi.org/', $doi)" />
</url>
</document>
</xsl:template>
</xsl:stylesheet>
The prefix defines a namespace for the XML elements.
For your stylesheet to work, the namespace declaration needs to match that in your input XML. Replace
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:bib="http://www.bib.com/xml">
with
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:bib="http://elsevier.co.uk/namespaces/2001/bibliotek">
This results in the following output XML:
<?xml version="1.0" encoding="utf-8"?>
<searchresult xmlns:bib="http://elsevier.co.uk/namespaces/2001/bibliotek">
<document>
<title>
Mesothelin Virus-Like Particle Immunization Controls Pancreatic Cancer Growth through CD8+ T Cell Induction and Reduction in the Frequency of CD4+foxp3+ICOS- Regulatory T Cells
</title>
<snippet>
Mesothelin Virus-Like Particle Immunization Controls Pancreatic Cancer Growth through CD8+ T Cell Induction and Reduction in the Frequency of CD4+foxp3+ICOS- Regulatory T Cells
</snippet>
<url>http://dx.doi.org/10.1371/journal.pone.0068303</url>
</document>
</searchresult>
I have the following xml:
<RootNode xmlns="http://someurl/path/path/path">
<Child1>
<GrandChild1>Value</GrandChild1>
<!-- Lots more elements in here-->
</Child1>
</RootNode>
I have the following xslt:
<xsl:stylesheet version="1.0" xmlns="http://someurl/path/path/path" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<NewRootNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<NewChild1>
<xsl:for-each select="RootNode/Child1">
<NewNodeNameHere>
<xsl:value-of select="GrandChild1"/>
</NewNodeNameHere>
<!-- lots of value-of tags in here -->
</xsl:for-each>
</NewChild1>
</NewRootNode >
</xsl:template>
</xsl:stylesheet>
The problem: this is the my result:
<?xml version="1.0" encoding="utf-8"?>
<NewRootNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<NewChild1 />
</NewRootNode>
I am expecting to see:
<?xml version="1.0" encoding="utf-8"?>
<NewRootNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<NewChild1>
<NewNodeNameHere>Value</NewNodeNameHere>
<!-- Other new elements with values from the xml file -->
</NewChild1>
</NewRootNode>
I am missing of the information inside of NewChild1 that should be there.
I think my for-each select is correct, so the only thing I can think of is that there is a problem with the namespace in the Xml and the namespace in the xslt. Can anybody see what I'm doing wrong?
The problem is caused by the namespaces.
Since the xml defines xmlns="http://someurl/path/path/path", it is not in the default namespace anymore.
You can define that namespace with an name like xmlns:ns="http://someurl/path/path/path" in the xsl, and then use that name in the XPath expression.
The following works for me:
<xsl:stylesheet version="1.0" xmlns:ns="http://someurl/path/path/path" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<NewRootNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<NewChild1>
<xsl:for-each select="ns:RootNode/ns:Child1">
<NewNodeNameHere>
<xsl:value-of select="ns:GrandChild1"/>
</NewNodeNameHere>
<!-- lots of value-of tags in here -->
</xsl:for-each>
</NewChild1>
</NewRootNode >
</xsl:template>
</xsl:stylesheet>
The stylesheet namespace should be http://www.w3.org/1999/XSL/Transform instead of http://someurl/path/path/path.
Also, since the input XML uses a namespace all your XPath expressions should be namespace-qualified:
<xsl:template match="/" xmlns:ns1="http://someurl/path/path/path">
<NewRootNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<NewChild1>
<xsl:for-each select="ns1:RootNode/ns1:Child1">
<NewNodeNameHere>
<xsl:value-of select="ns1:GrandChild1"/>
</NewNodeNameHere>
<!-- lots of value-of tags in here -->
</xsl:for-each>
</NewChild1>
</NewRootNode>
</xsl:template>
I'm trying to process an SVG file with XSLT. I am having behaviors I don't understand, that involves the doctype declaration.
Here are two tests I've done. The first one gives me the expected result and the second gives me a result I don't understand. (tested with saxon and xalan).
Stylesheet used for the two tests :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="text()" >
</xsl:template>
<xsl:template match="/">
<xsl:text>/</xsl:text>
<xsl:apply-templates />
</xsl:template>
<xsl:template match="svg">
<xsl:text>svg</xsl:text>
<xsl:apply-templates />
</xsl:template>
</xsl:stylesheet>
Test n°1
source file :
<?xml version="1.0"?>
<svg width="768" height="430">
</svg>
result :
/svg
Test n°2
source file :
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN"
"http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd">
<svg width="768" height="430">
</svg>
result :
/
Why does the doctype declaration modifies the behavior of the processing ?
The SVG elements are in the SVG namespace.
The DTD defines this, so:
<xsl:template match="svg">
is matching an element with the name of svg, but in no namespace. All the elements in the XML document are in the SVG namespace and this template doesn't match any node.
This explains the output.
Solution: Replace the template matching svg with one that matches svg in the SVG namespace, as in the following transformation:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:s="http://www.w3.org/2000/svg"
>
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="text()" >
</xsl:template>
<xsl:template match="/">
<xsl:text>/</xsl:text>
<xsl:apply-templates />
</xsl:template>
<xsl:template match="s:svg">
<xsl:text >svg</xsl:text>
<xsl:apply-templates />
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN"
"http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd">
<svg width="768" height="430" >
</svg>
the wanted result is produced:
/svg
Update:
Several people asked me "How a DTD can set a (default) namespace?"
Here is an answer: XML and DTDs with it were made a W3C Recommendation before namespaces made it. In pre-namespace XML a namespace declaration is simply an attribute.
DTD's can specify "default attributes" -- attributes, which may be ommitted from an instance but will be automatically added with a default value.
So, one way to define a default namespace in a DTD is to define an xmlns default attribute for the top element of the document.