I have xml like this
<mets:mets xmlns:mets="http://www.loc.gov/METS/">
<mets:fileSec>
<mets:fileGrp ID="REP1">
<mets:file ID="FL1">
<mets:FLocat LOCTYPE="URL" xlin:href="1.jpg" xmlns:xlin="http://www.w3.org/1999/xlink"/>
</mets:file>
</mets:fileGrp>
<mets:fileGrp ID="REP2">
<mets:file ID="FL2">
<mets:FLocat LOCTYPE="URL" xlin:href="1.tif" xmlns:xlin="http://www.w3.org/1999/xlink"/>
</mets:file>
</mets:fileGrp>
<mets:fileGrp ID="REP3">
<mets:file ID="FL3">
<mets:FLocat LOCTYPE="URL" xlin:href="2.jpg" xmlns:xlin="http://www.w3.org/1999/xlink"/>
</mets:file>
</mets:fileGrp>
</mets:fileSec>
</mets:mets>
I want to get as output IDs only files with jpg extention -> FL1, FL3.
I have problems with my xsl file :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:mets="http://www.loc.gov/METS/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mods="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-0.xsd"
exclude-result-prefixes="xlin">
<xsl:output method="html" omit-xml-declaration="yes" indent="yes" />
<xsl:template match="/">
<xsl:for-each select="//mets:fileSec/mets:fileGrp/mets:file">
<xsl:variable name="currentID" select="#ID" />
<xsl:for-each select="//mets:fileSec/mets:fileGrp/mets:file/mets:FLocat">
<xsl:variable name="testVariable" select="#xlink:href" xmlns:xlink="http://www.w3.org/1999/xlink" />
<xsl:choose>
<xsl:when test="contains($testVariable, '.jpg')"><xsl:value-of select="$currentID"/>,</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
But after transform I get error output as : FL1,FL1,FL2,FL2,FL3,FL3,
Please, help me with XSL.
Thank you!
Would something like this work for you?
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mets="http://www.loc.gov/METS/"
xmlns:xlin="http://www.w3.org/1999/xlink">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:for-each select="mets:mets/mets:fileSec/mets:fileGrp/mets:file[contains(mets:FLocat/#xlin:href, '.jpg')]">
<xsl:value-of select="#ID"/>
<xsl:if test="position()!=last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Related
I'm trying to generate an xml with the help of xslt templates and I have a tricky thing to do:
I have to generate a certain number of elements that have same tags but with different values inside them. Example of xslt stylesheet:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="NbOfBatches"/>
<xsl:param name="wholeTag"/>
<xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<Document xmlns="urn:something" xmlns:file="someUrn>
<FileAppHdr>
<file:NbOfBatches><xsl:value-of select="$NbOfBatches"></xsl:value-of></file:NbOfBatches>
<xsl:call-template name="selects">
<xsl:with-param name="i">1</xsl:with-param>
<xsl:with-param name="count"><xsl:value-of select="$NbOfBatches"/></xsl:with-param>
</xsl:call-template>
</FileAppHdr>
</Document>
</xsl:template>
<xsl:template name="selects">
<xsl:param name="i" />
<xsl:param name="count" />
<xsl:if test="$i <= $count">
<xsl:call-template name="credit">
<xsl:with-param name="param0"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="$i <= $count">
<xsl:call-template name="selects">
<xsl:with-param name="i">
<xsl:value-of select="$i + 1"/>
</xsl:with-param>
<xsl:with-param name="count">
<xsl:value-of select="$count"/>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="credit">
<xsl:param name="param0"/>
<CreditTransfer>
<xsl:value-of select="$param0"/>
</CreditTransfer>
</xsl:template>
</xsl:stylesheet>
In this way, I can use Saxon or JAXP and call .setParameter() for NbOfBatches, it will generate that number of tags. However is there a way to generate / modify name of param0 inside CreditTransfer so that I can loop through data in Java and use .setParameter("param1", value1) and so on ?
Thank you
Rather than trying to pass structured data as a stylesheet parameter, why not generate that structured data as XML and pass that XML document as the source document of the transformation?
As an example, imagine a source XML document with param0 in each Batch:
<Batches>
<Batch>
<param0>it was the best of times</param0>
</Batch>
<Batch>
<param0>it was the worst of times</param0>
</Batch>
<Batch>
<param0>it was the age of wisdom</param0>
</Batch>
<Batch>
<param0>it was the age of foolishness</param0>
</Batch>
</Batches>
with a simplified version of your stylesheet:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<Document xmlns:file="someUrn">
<FileAppHdr>
<file:NbOfBatches><xsl:value-of select="count(//Batch)"/></file:NbOfBatches>
<xsl:for-each select="//Batch">
<xsl:call-template name="selects">
<xsl:with-param name="param0" select="param0" />
</xsl:call-template>
</xsl:for-each>
</FileAppHdr>
</Document>
</xsl:template>
<xsl:template name="selects">
<xsl:param name="param0" />
<xsl:call-template name="credit">
<xsl:with-param name="param0" select="$param0" />
</xsl:call-template>
</xsl:template>
<xsl:template name="credit">
<xsl:param name="param0"/>
<CreditTransfer>
<xsl:value-of select="$param0"/>
</CreditTransfer>
</xsl:template>
</xsl:stylesheet>
produces this output:
<Document xmlns:file="someUrn">
<FileAppHdr>
<file:NbOfBatches>4</file:NbOfBatches>
<CreditTransfer>it was the best of times</CreditTransfer>
<CreditTransfer>it was the worst of times</CreditTransfer>
<CreditTransfer>it was the age of wisdom</CreditTransfer>
<CreditTransfer>it was the age of foolishness</CreditTransfer>
</FileAppHdr>
</Document>
It's fairly trivial to generate XML from structured data in Java using the Saxon sapling classes. https://www.saxonica.com/html/documentation10/javadoc/net/sf/saxon/sapling/package-summary.html
I am trying to include parent nodes of the node I am copying.
Here is the sample file:
<A>
<B>
<C1>Text Value</C1>
<C2></C2>
<C3></C3>
<C4></C4>
</B>
</A>
I would like the output to be:
<A>
<B>
<C1>Text Value</C1>
</B>
</A>
Here is my xslt:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
<xsl:template match="/A/B/C1">
<xsl:copy>
<xsl:apply-templates select="/A/B/C1"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
However, my output does not show the parent nodes.
Edit:
C1 will always have the same Xpath. I would also like to include the Text of the node.
Here's one way to produce the result you show:
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:template match="*">
<xsl:copy>
<xsl:apply-templates select="*[descendant-or-self::C1] | C1/text()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Edit: C1 will always have the same Xpath.
Well, then here's another:
<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:template match="/">
<A>
<B>
<xsl:copy-of select="A/B/C1"/>
</B>
</A>
</xsl:template>
</xsl:stylesheet>
how to replace the child tag name with xsl.
here the below is my structure of xml.
<Checkpax xmlns="http://xml.api.com/test">
<customerLevel>
<customerDetails>
<paxDetails>
<surname>MUKHERJEE</surname>
<type>A</type>
<gender>M</gender>
</paxDetails>
<otherPaxDetails>
<givenName>JOY</givenName>
<title>MR</title>
<age>11</age>
</otherPaxDetails>
<otherPaxDetails>
<title>MR</title>
</otherPaxDetails>
</customerDetails>
<staffDetails>
<staffInfo/>
<staffCategoryInfo>
<attributeDetails>
<attributeType>NA</attributeType>
</attributeDetails>
</staffCategoryInfo>
</staffDetails>
<productLevel>
<legLevel>
<legLevelIndicator>
<statusDetails>
<indicator>abc</indicator>
<action>1</action>
</statusDetails>
</legLevelIndicator>
</legLevel>
</productLevel>
<CustomerLevel>
<legLevel>
<legLevelIndicator>
<statusDetails>
<indicator>cde</indicator>
<action>1</action>
</statusDetails>
</legLevelIndicator>
</legLevel>
</CustomerLevel>
</customerLevel>
</Checkpax>
The below is my XSL file
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="customerLevel/productLevel/legLevel/legLevelIndicator/statusDetails">
<statusInformation>
<xsl:apply-templates select="#*|node()" />
</statusInformation>
</xsl:template>
</xsl:stylesheet>
here the statusDetails name should be changed as staffInformation inside the ProductLevel/LeglevelIndicator . Kindly give me the suggestion for doing this.
The below is expected result
<Checkpax xmlns="http://xml.api.com/test">
<customerLevel>
<customerDetails>
<paxDetails>
<surname>MUKHERJEE</surname>
<type>A</type>
<gender>M</gender>
</paxDetails>
<otherPaxDetails>
<givenName>JOY</givenName>
<title>MR</title>
<age>11</age>
</otherPaxDetails>
<otherPaxDetails>
<title>MR</title>
</otherPaxDetails>
</customerDetails>
<staffDetails>
<staffInfo/>
<staffCategoryInfo>
<attributeDetails>
<attributeType>NA</attributeType>
</attributeDetails>
</staffCategoryInfo>
</staffDetails>
<productLevel>
<legLevel>
<legLevelIndicator>
<statusInformation>
<indicator>abc</indicator>
<action>1</action>
</statusInformation>
</legLevelIndicator>
</legLevel>
</productLevel>
<CustomerLevel>
<legLevel>
<legLevelIndicator>
<statusDetails>
<indicator>cde</indicator>
<action>1</action>
</statusDetails>
</legLevelIndicator>
</legLevel>
</CustomerLevel>
</customerLevel>
</Checkpax>
the statusDetails name should be changed as staffInformation inside
the ProductLevel/LeglevelIndicator
Try it this way:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://xml.api.com/test"
exclude-result-prefixes="ns0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ns0:productLevel/ns0:legLevel/ns0:legLevelIndicator/ns0:statusDetails">
<staffInformation xmlns="http://xml.api.com/test">
<xsl:apply-templates/>
</staffInformation>
</xsl:template>
</xsl:stylesheet>
My source XML is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:DriverResponse xmlns:ns2="com/rsa/eosago/schema-1.1" xmlns:ns3="com/rsa/dkbm/schema-1.5">
<IDCheckDriver>84714718</IDCheckDriver>
<ErrorList>
<ErrorInfo>
<Code>2</Code>
<Message>Принят в обработку</Message>
</ErrorInfo>
</ErrorList>
</ns2:DriverResponse>
Wanted output:
<?xml version="1.0" encoding="UTF-8"?>
<rsa:DriverStatusRequest xmlns:rsa="com/rsa/eosago/schema-1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<InsurerID>18800000</InsurerID>
<IDCheckDriver>84714718</IDCheckDriver>
</rsa:DriverStatusRequest>
I expect this output using this XSL wich is called from Apache Camel:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:param name="RSA-InsurerID"/>
<xsl:param name="EOSAGO-schema-version"/>
<xsl:param name="schema" select="concat('com/rsa/eosago/schema-', $EOSAGO-schema-version)"/>
<xsl:variable name="schemaUrlDummy">
<xsl:element name="ns2:dummy" namespace="{$schema}"/>
</xsl:variable>
<xsl:variable name="NS" select="ext:node-set($schemaUrlDummy)/*/namespace::ns2"/>
<xsl:template match="/">
<xsl:element name="rsa:DriverStatusRequest" namespace="com/rsa/eosago/schema-{$EOSAGO-schema-version}">
<InsurerID>
<xsl:value-of select="$RSA-InsurerID"/>
</InsurerID>
<xsl:element name="IDCheckDriver">
<xsl:copy-of select="namespace::*[not(name()='ns2')]"/>
<xsl:copy-of select="$NS"/>
<xsl:value-of select="ns2:DriverResponse/IDCheckDriver"/>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Camel settings:
<setHeader headerName="RSA-InsurerID">
<constant>18800000</constant>
</setHeader>
<setHeader headerName="EOSAGO-schema-version">
<constant>1.2</constant>
</setHeader>
<to uri="xslt:com/rsa/eosago/xsl/DriverResponse2DriverStatusRequest.xsl"/>
The problem is that i get this error stacktrace
Failed to resolve endpoint: xslt://com/rsa/eosago/xsl/DriverResponse2DriverStatusRequest.xsl due to: Namespace prefix 'ns2' is undeclared.
Failed to resolve endpoint: xslt://com/rsa/eosago/xsl/DriverResponse2DriverStatusRequest.xsl due to: Namespace prefix 'ns2' is undeclared.
javax.xml.transform.TransformerConfigurationException: Namespace prefix 'ns2' is undeclared.
Why compiler throws exception on namespace that was created dinamically?
This is very confusing. Why can't you do simply:
<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="RSA-InsurerID"/>
<xsl:param name="EOSAGO-schema-version"/>
<xsl:template match="/*">
<xsl:element name="rsa:DriverStatusRequest" namespace="com/rsa/eosago/schema-{$EOSAGO-schema-version}">
<InsurerID>
<xsl:value-of select="$RSA-InsurerID"/>
</InsurerID>
<IDCheckDriver>
<xsl:value-of select="IDCheckDriver"/>
</IDCheckDriver>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Working demo: http://xsltransform.net/pPzifqv
I was trying to find a way to convert the XML tags to their respective unique address like xPath. Nd I found an XSLT, where XML is processed and the unique address is created only for the nodes which doesnt have child elements and with attributes. [link]:Generate/get xpath from XML node java
XSLT :
<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:variable name="vApos">'</xsl:variable>
<xsl:template match="*[#* or not(*)] ">
<xsl:if test="not(*)">
<xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
<xsl:value-of select="concat('=',$vApos,.,$vApos)"/>
<xsl:text>
</xsl:text>
</xsl:if>
<xsl:apply-templates select="#*|*"/>
</xsl:template>
<xsl:template match="*" mode="path">
<xsl:value-of select="concat('/',name())"/>
<xsl:variable name="vnumPrecSiblings" select=
"count(preceding-sibling::*[name()=name(current())])"/>
<xsl:if test="$vnumPrecSiblings">
<xsl:value-of select="concat('[', $vnumPrecSiblings +1, ']')"/>
</xsl:if>
</xsl:template>
<xsl:template match="#*">
<xsl:apply-templates select="../ancestor-or-self::*" mode="path"/>
<xsl:value-of select="concat('[#',name(), '=',$vApos,.,$vApos,']')"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
when passed to this
<?xml version="1.0" encoding="UTF-8"?>
<root>
<main>
<tag1>001</tag1>
<tag2>002</tag2>
<tag3>
<tag4>004</tag4>
</tag3>
<tag2>002</tag2>
<tag5>005</tag5>
</main>
</root>
produces
/root/main/tag1='001' /root/main/tag2='002' /root/main/tag3/tag4='004' /root/main/tag2[2]='002' /root/main/tag5='005'
So I need the xslt to generate in the following way
/root
/root/main
/root/main/tag1
/root/main/tag2
/root/main/tag3
/root/main/tag3/tag4
/root/main/tag2[2]
/root/main/tag5
Also I dont need values. So please help me with this
Your result could be produced rather simply by:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="*">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="name()" />
<xsl:variable name="i" select="count(preceding-sibling::*[name()=name(current())])"/>
<xsl:if test="$i">
<xsl:value-of select="concat('[', $i + 1, ']')"/>
</xsl:if>
<xsl:if test="position()!=last()">
<xsl:text>/</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
<xsl:apply-templates select="*"/>
</xsl:template>
</xsl:stylesheet>
Note that this does not process attributes (or any other type of nodes other than elements).