Is it possible to check an elements ComplexType?
i have this (simplified):
complexType Record
complexType Customer extension of Record
complexType Person extension of Record
<xsl:template match="/">
<records>
<xsl:apply-templates />
</records>
</xsl:template>
<xsl:template match="!!! TYPECHECK FOR RECORD !!!" name="Record">
<record><xsl:value-of select="." /></record>
</xsl:template>
is it possible to check elementstype incl. inheritence?
i dont know the elements name only that they are a subtype of Record.
schema 1:
complexType name="Customer"
extension base="Record"
element name="customers"
element name="customer" type="Customer"
schema 2:
complexType name="Person"
extension base="Record"
element name="persons"
element name="person" type="Person"
schema ?:
complexType name="UnknownType"
extension base="Record"
element name="unknowns"
element name="unknown" type="UnknownType"
xml 1:
<customers>
<customer />
<customer />
</customers>
xml 2:
<persons>
<person />
<person />
</persons>
xml ?:
<?s>
<? />
<? />
</?s>
the xml input ist custom so i have to match by the type (i think)
In XPath 2.0 (and this means XSLT 2.0) one can use the instance-of operator:
. instance-of element(*, my:Record)
I'm not sure what you mean.
Different types have different tag names, and in xslt you should look at those to decide what type a node is.
Making sure a node indeed has a structure prescribed by your logic is not an xslt task. You should validate the document against a schema before passing it to an xslt processor to achieve this.
EDIT
I'm still not sure, but it seems like this question of mine could be of some help.
Related
I have the following XSLT template
<xsl:template match="/root">
<r>
<xsl:value-of select="transport/route[not(enddate)]/ship|car/fuel/litres"/>
</r>
</xsl:template>
Which I use to translate the following example XML
<root>
<transport>
<route>
<ship> <!-- this can be a car -->
<fuel>
<litres>
42
</litres>
</fuel>
</ship>
</route>
<route>
<enddate>2015-08-21</enddate>
<car>
<fuel>
<litres>
42
</litres>
</fuel>
</car>
</route>
</transport>
</root>
Notice that under route I can have a ship OR a car.
I can't find a way to reduce the xpath exression to only cover for the choice between ship and car
<xsl:value-of select="transport/route[not(enddate)]/ship|car/fuel/litres"/>
To make the above work I have to change it to this:
<xsl:value-of
select="transport/route[not(enddate)]/ship/fuel/litres |
transport/route[not(enddate)]/car/fuel/litres"/>
but I that feels as I'm copying to much of the expression and violates my DRY nature. I tried transport/route[not(enddate)][car|ship]/fuel/litres but without success.
What should the expression be if I want to get rid of the duplication of the xpath?
One way to write your expression is as follows:
<xsl:value-of select="transport/route[not(enddate)]/*[self::car or self::ship]/fuel/litres"/>
Alternatively, if a route element can contain only only child element (whether ship, car or something else, you could also write this:
<xsl:value-of select="transport/route[not(enddate)][ship or car]/*/fuel/litres"/>
Using an XSLT 2.0 or 3.0 processor you can use <xsl:value-of
select="transport/route[not(enddate)]/(ship | car)/fuel/litres"/> but be aware that value-of with a version="2.0" or version="3.0" stylesheet outputs a sequence of values of the selected sequence and not the first value in the selected sequence like version="1.0" does.
Using XSLT 1.0
Is it possible to filter many to many attributes, i mean as below example:
"../../../../fieldmap/field[#name" i.e. more then 1 elements as fieldmap containing "field/#name" attribute are exists and it is comparing with definition/#title and there too more then one definition element exists containing #title.
EXAMPLE:
<xsl:for-each select="../../../../fieldmaps/field[#name=../destination/#title]">
Can you please suggest me how it could possible to achieve -- if field containing #name existed in any of defination/#title then only those records should be process within for-each loop?
(as now, it looks, it will just compare with first #title attribute and consider all fieldmaps/field/#name attributes)
Thanks
You can achieve that using a variable:
<xsl:variable name="titles" select="../destination/#title"/>
<!--now "titles" contains a nodeset with all the titles -->
<xsl:for-each select="../../../../fieldmaps/field[#name=$titles]">
<!-- you process each field with a name contained inside the titles nodeset -->
</xsl:for-each>
Here you have a simplified example:
INPUT:
<parent>
<fieldmaps>
<field name="One"/>
<field name="Two"/>
<field name="Three"/>
</fieldmaps>
<destinations>
<destination title="One"/>
<destination title="Two"/>
</destinations>
</parent>
TEMPLATE:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- ++++++++++++++++++++++++++++++++ -->
<xsl:template match="parent">
<Results>
<xsl:variable name="titles" select="destinations/destination/#title"/>
<xsl:for-each select="fieldmaps/field[#name=$titles]">
<Result title="{#name}"/>
</xsl:for-each>
</Results>
</xsl:template>
<!-- ++++++++++++++++++++++++++++++++ -->
</xsl:stylesheet>
OUTPUT:
<Results>
<Result title="One"/>
<Result title="Two"/>
</Results>
I hope this helps!
Referring to query XSLT to translate Zotero xml output to FMPXMLRESULT xml?, how in the XSLT do I refer to a mod such as:
<genre authority="marcgt"> book </genre>
(There are multiple mods beginning genre authority, each with a different parameter. So what is the syntax in the XSLT for that? I tried the following, but Filemaker says there's a syntax error.
<COL>
<DATA>
<xsl:value-of select="mod:genre authority=""marcgt""" />
</DATA>
</COL>
The select is looking for a node to pick, it seems like you are trying to point it to:
<xsl:value-of select="mod:genre[#authority='marcgt']" />
I am new to XSLT so excuse me if this is a noob question.
Let's say I have this XML document (one hotel element with 2 private_rates):
<hotel>
<private_rates>
<private_rate>
<id>1</id>
</private_rate>
<private_rate>
<id>2</id>
</private_rate>
</private_rates>
</hotel>
Is there any way to use XSLT to transform it into 2 hotel elements, each with one private rate ?
<hotel>
<private_rates>
<private_rate>
<id>1</id>
</private_rate>
</private_rates>
</hotel>
<hotel>
<private_rates>
<private_rate>
<id>2</id>
</private_rate>
</private_rates>
</hotel>
How would the XSLT for that look like? Any help will be greatly appreciated! thanks.
As an alternative to Jollymorphic's solution, my preference would be
<xsl:template match="private_rates">
<hotel>
<xsl:copy-of select="."/>
</hotel>
</xsl:template>
Since a legal XML document has to have a single, containing document element, I presume that this sequence of hotels is going inside something. That being said, how about this:
<xsl:template match="hotel">
<xsl:for-each select="private_rates/private_rate">
<hotel>
<private_rates>
<xsl:copy>
<xsl:apply-templates />
</xsl:copy>
</private_rates>
</hotel>
</xsl:for-each>
</xsl:template>
The apply-templates usage here presumes that you also have an identity template in your stylesheet that will copy source content that isn't more specifically matched by other templates (such as this one).
Underscores are frowned upon in element and attribute names, incidentally.
I am have trouble converting my xml using XSLT back to xml in the convert format, this is my XML below:
<?xml version="1.0" encoding="UTF-8" ?>
<DOCUMENTS>
<DOCUMENTS_INFO DOCUMENT_COUNT="8" />
<DOCUMENT_GROUP NAME="Invoices" DISPLAY_NAME="INVOICES">
<DOCUMENT>
<FIELD>
<name>USER</name>
<display_name>Deposited by</display_name>
<value>machine</value>
</FIELD>
<FIELD>
<name>DATE</name>
<display_name>Archive date</display_name>
<value>21/05/2009</value>
</FIELD>
</DOCUMENT>
<DOCUMENT>
<FIELD>
<name>USER</name>
<display_name>Deposited by</display_name>
<value>machine</value>
</FIELD>
<FIELD>
<name>DATE</name>
<display_name>Archive date</display_name>
<value>21/06/2009</value>
</FIELD>
</DOCUMENT>
</DOCUMENT_GROUP>
</DOCUMENTS>
I need to convert so I can read it into my datagrid in ASP.NET so the output would be something like this below:
Deposited by | Archive date
machine | 21/05/2009
machine | 21/06/2009
Many Thanks
You don't really need to do any conversion at all. If you want to pull the data into a dataset or something so that you can display it, all you need is a little bit of XPath.
The XPath to get all DOCUMENT elements:
//DOCUMENT
And the XPath to get a pair of value elements based on the name value, based in a DOCUMENT element:
FIELD[name = 'USER']/value
FIELD[name = 'DATE']/value
So depending on the technology you use to parse the XML, you'll basically need a loop over the first expression, and then run the following two expressions on the results of the first loop. In XSL it'll look something like this:
<xsl:template match="/">
<xsl:for-each select="//DOCUMENT">
<xsl:value-of select="FIELD[name = 'USER']/value"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="FIELD[name = 'DATE']/value"/>
</xsl:for-each>
</xsl:template>
Like anything, there's more than one way to do this. You can use a template as well:
<xsl:template match="/">
<xsl:apply-templates select="//DOCUMENT" />
</xsl:template>
<xsl:template match="DOCUMENT">
<xsl:value-of select="FIELD[name = 'USER']/value"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="FIELD[name = 'DATE']/value"/>
</xsl:template>
Both of these will give the output you gave as an example, but you're probably better off reading the XPath values directly into a dataset or writing your own adapter to pull these values out and load them directly into a datagrid.