XSLT Namespace troubles - xslt

In the next step of a project I am working on I am having a problem with namespace statements in an xslt file. I admit that the problem is likely identical to that found in this question: Filemaker XSL Importing blank fields. However, I'm not able to understand the solution there and feel that perhaps the answer may be a bit more simplistic, i.e. I've mucked up the syntax somehow.
The xml I'm working with is:
<?xml version="1.0" encoding="utf-8" ?>
<ledesxml xmlns="http://www.ledes.org/ledes20.xsd">
<firm>
<lf_vendor_id>test</lf_vendor_id>
</firm>
</ledesxml>
The xslt I'm currently using is:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns="http://www.ledes.org/ledes2000.xsd"
xmlns:t="http://www.ledes.org/ledes2000.xsd"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<FMPXMLRESULT xmlns="http://www.filemaker.com/fmpxmlresult">
<METADATA>
<FIELD NAME="lf_vendor_id" TYPE="TEXT"/>
</METADATA>
<RESULTSET>
<ROW>
<COL><DATA><xsl:value-of select="/t:ledesxml/t:firm/t:lf_vendor_id"/></DATA></COL>
</ROW>
</RESULTSET>
</FMPXMLRESULT>
</xsl:template>
</xsl:stylesheet>
The import to Filemaker results in a new record without any data. The xml input here is an industry standard and doesn't change (at least for present purposes).
The use of name spaces here is a bit confusing and is based almost entirely on the namespaces used in the question linked above. Using a wild card in the "value-of select" statement does work, but as you might expect, grabs all the text in the xml sample and not just the data in which I am interested.
Since the import seems to work and the name space convention seems to have worked for another poster, I'm at a bit of a loss. Does anyone have some pointers as to where I've gone wrong?

The XML document has xmlns="http://www.ledes.org/ledes20.xsd" while the XSLT declares xmlns:t="http://www.ledes.org/ledes2000.xsd" with ledes2000 instead of ledes20. You will need to use the same namespace URL in both documents.

Related

XSLT - Extract and manipulate portion of XML data

The input XML:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Description><![CDATA[Audience: Andrew Reed, Senior Training Specialist, Microsoft Corporation<br/>This session is for individuals who spend significant time writing and creating documents and have some familiarity with Microsoft Word.<br/>Thanks.]]></Description>
</root>
The XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/root">
<div>
<xsl:value-of disable-output-escaping="yes" select="Description"/>
</div>
</xsl:template>
</xsl:stylesheet>
I need to add a couple of more BR tags after first occurrence of BR, that's after Audience line and before other description starts.
Can you please modify my XSLT to get the desired output?
So I want output like below:
Audience: Andrew Reed, Senior Training Specialist, Microsoft Corporation
This session is for individuals who spend significant time writing and creating documents and have some familiarity with Microsoft Word.
Thanks.
It would be nice if your input data had the <br/> elements as actual elements, instead of being escaped, so that they could be selected directly using XPath.
But since they are as they are, you can use regexp replace, relying on the assumption that they will always conform to a limited range of patterns. You will often be warned not to parse XML or HTML in general using regexps, and rightly so, because regexps aren't a general solution. But for limited uses they can be sufficient.
If I've guessed your requirements correctly, you could use something like
<xsl:value-of select="replace(Description, '<[Bb][Rr] ?/?>',
'
')"/>
That will give you the sample output you showed, as opposed to adding a couple of more BR tags after first occurrence of BR. It will tolerate some variation, e.g. <br> or <BR />.
This is assuming you can use XSLT 2.0, because replace() isn't available in 1.0. If you're limited to 1.0, please let me know.

XSL for-each loop is not working

I'm using Java to transform an XML document to text:
Transformer transformer = tFactory.newTransformer(stylesource);
transformer.transform(source, result);
This seems to work except when there are colons in the XML document. I tried this example:
XML file:
<?xml version="1.0" encoding="UTF-8"?>
<test:TEST >
<one.two:three id="my id" name="my name" description="my description" >
</one.two:three>
<one.two:three id="some id" name="some name" description="some description" />
</test:TEST>
XSL file:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xmi="http://www.omg.org/XMI"
xmlns:one.two="http://www.one.two/one.two:three" >
<xsl:output method="text" indent="yes" omit-xml-declaration="yes"/>
<xsl:variable name="myVariable">one.two:three</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="*[substring(name(),1,9)='test:TEST']" >
<xsl:for-each select="./$myVariable">
inFirstLoop
</xsl:for-each>
<xsl:for-each select="./one.two:three">
inSecondLoop
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
The result of the transformation I'm getting is a single line:
inFirstLoop
I'm expecting 4 lines of output
inFirstLoop
inFirstLoop
inSecondLoop
inSecondLoop
How do I fix this? Any help is greatly appreciated. Thanks.
There are multiple things wrong here. I'm surprised your transformation managed to run at all, instead of failing on parse errors and other errors.
One big problem is that your input XML uses namespace prefixes (that's what the colons are for) without declaring them. Declarations like
xmlns:one.two="http://www.one.two/one.two:three"
need to be in the source XML, as well as in the XSL. Otherwise your source XML is not well-formed (according to namespace rules).
A second problem is the XPath expression
./$myVariable
which should have thrown an error. I think what you wanted was
*[name() = $myVariable]
The third change I would make is not an error in the XSLT, but just a poor way of doing things... If you want to match <test:TEST>, you should use namespace tools to refer to namespaces. Therefore, instead of
<xsl:template match="*[substring(name(),1,9)='test:TEST']" >
use
<xsl:template match="test:TEST">
Much cleaner. Then you need to put in a namespace declaration on the outermost element of the stylesheet, as you already have to do in the input XML document:
xmlns:test="...test..."
XML namespaces, like driving a car, are a topic better learned from a little training than by trial-and-error. Reading a brief article like this will help you avoid a lot of confusion and pain down the road.

XSLT help in declaring namespace

need some help in resolving the following issue. I need to transform the below input(XML) to the mentioned output(XML).
<Header>
<End_Date xsi:nil="true"/>
<Header>
To the following format.
<Header>
<End_Date xsi:nil="true" xmlns:xsi"http://www.w3.org/2001/XMLSchema"/>
<Header>
This is the stylesheet:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<HEADER>
<xsl:for-each select="HEADER">
<xsl:sequence select="(./#node(), ./node())"/>
</xsl:for-each>
</HEADER>
</xsl:template>
</xsl:stylesheet>
Thanks in advance.
Gabriel
Am I right in thinking you want to reproduce a nearly exact copy of the input XML, with the addition of the xsi namespace declaration that is lacking from the input?
First, as it is now, your input is not well-formed XML, just because of the lacking xsi namespace declaration. Hence, there's no way to use XSLT for adding it: any XSLT processor will choke on the input's non-well-formedness.
Second, you have to check case sensitivity: currently, no input nodes are matched by the <xsl:for-each select="HEADER"> select expression. If you change it to "Header", the template rule will indeed replace the <Header> input with <HEADER>, whose content is copied identically. But... only if you have the namespace declarations in the input right...
So, if the purpose is indeed to 'upgrade' non-well-formed XML to a well-formed version, I'd suggest to look for other tools, such as Perl, Awk, or any other simple search/replace solution that operates on plain text and could just add the missing namespace declaration to the document element:
<Header xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<End_Date xsi:nil="true"/>
</Header>
(Of course, you could also make use of XSLT 2.0's unparsed-text($href) function that lets you read any file as unparsed text, which you could then further process with <xsl:analyze-string>. See Michael Kay's article Up-conversion using XSLT 2.0 for further inspiration. Since this a rather awkward way to process non-XML with an XML tool, I give this merely for completeness -- if adding the namespace prefix is the only problem to be solved, I'd definitely go for a cheaper search/replace option.)
Hope this helps,
Ron

xml not showing in Browser

Below is the input xml :
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="value-of.xsl"?>
<MemeberDetails>
<Employee>
<Name>Madhu</Name>
<Sex>Male</Sex>
<DOB>2/10/1982</DOB>
<Address>JP Nagar ,Bangalore</Address>
<MemberId>094631</MemberId>
<Designation>SSE</Designation>
<Department>SG</Department>
</Employee>
</MemeberDetails>
where, i am referring value-of.xsl file using HREF in above xml. and this file is residing in same folder.
Below is the value-of.xslt file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<CGIEmployeeDetails>
<PersonalDetails>
<Name>
<xsl:value-of select="/MemeberDetails/Employee/Name"/>
</Name>
<Gender>
<xsl:value-of select="/MemeberDetails/Employee/Sex"/>
</Gender>
<ResidentialAddress>
<xsl:value-of select="/MemeberDetails/Employee/Address"/>
</ResidentialAddress>
</PersonalDetails>
<WorkingDetails>
<PSAID>
<xsl:value-of select="//MemberId"/>
</PSAID>
<Designation>
<xsl:value-of select="/MemeberDetails/Employee/Designation"/>
</Designation>
<Department>
<xsl:value-of select="/MemeberDetails/Employee/Department"/>
</Department>
</WorkingDetails>
</CGIEmployeeDetails>
</xsl:template>
</xsl:stylesheet>
When i run above xml in browser , the output will result as text but not as XML .
If i use editor like Oxygen and transform the same xml file , the output will be XML.
I am not getting why browser is failing to transform a XML output ?
Is there anything to do with browser ?
In browsers, the "XML format" view is mostly a stylesheet adding syntax highlighting and Emacscript event handlers (show and hide chlids nodes, etc.).
So, when the document has a XSLT stylesheet PI, browsers don't run that "XML format" stylesheet but they try to render the transformation result. This intent is not the same for each browser. Only one thing is guaranteed: if it's proper XHTML or HTML, is render as is.
If the transformation result is not proper XHTML nor HTML (plain text, other XML vocabulary), the render mechanism varies from one to another: i.e Chrome is the only one showing nothing for unknown XML vocabulary, others render this as HTML anyway (rendering only text).
Are you using internet explorer? That is the only browser I know of that would completely ignore your XSL stylesheet
#Alejandro provided a good explanation.
Using IE, you can see the result of the XSLT transformation by right-clicking on the IE window and selecting "View Source"

Generate dynamic xmlns

I would like to dynamically generate xmlns attributes.
I want to generate this in XSL :
<Common:MainPageBase xmlns:Common="clr-namespace:ThisPartIsDynamic;assembly=ThisPartIsDynamic">
</Common:MainPageBase>
How can I do that in XSL?
Thanks,
Alex
Update:
To be more precise, here is what I need to generate. The parts that I want to be able to change with variables are "THISPARTISDYNAMIC":
<Common:MainPageBase
xmlns:Common="clr-namespace:THISPARTISDYNAMIC;assembly=THISPARTISDYNAMIC"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:df="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
xmlns:controlsToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
xmlns:basics="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:uc="clr-namespace:THISPARTISDYNAMIC"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"
></Common:MainPageBase>
Any ideas?
You can set the namespace of an element dynamically:
<param name="ns1" >http://localhost/ns1</param>
...
<xsl:element name="test" namespace="{$ns1}" >... </xsl:element>
But that doesn't output a namespace prefix -- it changes the default namespace on that element.
I don't think there is a way to output the prefixes with a dynamic namespace URI.
Something like: <xyz:test xmlns:xyz="{$ns1}">
outputs exactly that literally: <xyz:test xmlns:xyz="{$ns1}">
If that is really the exact output you require, then I think you either have
to modify the serializer, or just produce the output with a placeholder URI and
do a text replacement on the output xml text.
[ XSLT does not process XML syntax. It processes XML trees.
Parsing the input and serializing the output are outside of it's realm. ]
Take a look at the article Namespaces in XSLT, and at the section XSLT 1.0: Creating dynamic namespace nodes in particular.
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes"/>
<xsl:variable name="vDynamicPart1" select="'DynPArt1'"/>
<xsl:variable name="vDynamicPart2" select="'DynPArt2'"/>
<xsl:template match="/">
<xsl:element name="Common:MainPageBase"
namespace="clr-namespace:{$vDynamicPart1};assembly={$vDynamicPart2}"/>
</xsl:template>
</xsl:stylesheet>
when applied on any XML document (not used), produces the desired result.