xpath 2.0: filter sequence using another sequence - xpath-2.0

I'm trying to filter a sequence by using another sequence in a predicate:
Here my xpath:
doc('files.xml')/files/file[path = //reference]
here the xml files:
files.xml
<?xml version="1.0" encoding="UTF-8"?>
<files>
<file>
<path>d0002/000000338179.pdf</path>
<file>
<path>d0002/000000338179.JPG</path>
</file>
</file>
<file>
<path>d0002/000000341922.pdf</path>
</file>
<file>
<path>d0002/000000342768.pdf</path>
</file>
</files>
references
<?xml version="1.0" encoding="UTF-8"?>
<references>
<reference>d0002/000000338179.pdf</reference>
<reference>d0002/000000341922.pdf</reference>
</references>
I can't get it to work, any hint is greatly appreciated.
Vlax
EDIT
based on the answer from #Jirka I came to a "pure" XPath expression:
for $file in doc('files.xml')/files/file,
$ref in //reference
return $file[path = $ref]/path

Probably context is changing there. So I tried use a variable and it seems to be working.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" indent="yes" />
<xsl:variable name="refs" select="//reference" />
<xsl:variable name="files" select="doc('files.xml')/files/file[path = $refs]" />
<xsl:template match="/">
<files>
<xsl:copy-of select="$files" />
</files>
</xsl:template>
</xsl:stylesheet>
This xslt gives a result
<?xml version="1.0" encoding="UTF-8"?>
<files xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<file>
<path>d0002/000000338179.pdf</path>
<file>
<path>d0002/000000338179.JPG</path>
</file>
</file>
<file>
<path>d0002/000000341922.pdf</path>
</file>
</files>

Related

XSLT 1.0 - How to only copy elements with values, or descendents with values

With XML like
<?xml version="1.0" encoding="utf-8"?>
<Products>
<Product>
<Sku />
<Suppliers>
<Supplier>
<Name />
</Supplier>
</Suppliers>
<Priority>1</Priority>
</Product>
<Product>
<Sku>123</Sku>
<Suppliers>
<Supplier>Jon</Supplier>
</Suppliers>
<Priority>3</Priority>
<e />
</Product>
</Products>
How to transform and only output if element has value, or descendent has a value?
(The 2nd 'filter template' filters empty, with match=*[not(node() )] , but only if no descendents)
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- When matching empty: do nothing -->
<xsl:template match="*[not(node())]">
<xsl:comment>filtering <xsl:value-of select="local-name()"/></xsl:comment>
</xsl:template>
Current output: (With debug-comments to identify names of filtered elements)
<?xml version="1.0" encoding="utf-8"?><Products>
<Product>
<!--filtering Sku-->
<Suppliers>
<Supplier>
<!--filtering Name-->
</Supplier>
</Suppliers>
<Priority>1</Priority>
</Product>
<Product>
<Sku>123</Sku>
<Suppliers>
<Supplier>Jon</Supplier>
</Suppliers>
<Priority>3</Priority>
<!--filtering e-->
</Product>
</Products>
Required output: (without comments)
<?xml version="1.0" encoding="utf-8"?><Products>
<Product>
<Priority>1</Priority>
</Product>
<Product>
<Sku>123</Sku>
<Suppliers>
<Supplier>Jon</Supplier>
</Suppliers>
<Priority>3</Priority>
</Product>
</Products>
Assume this requires a type of forward-look (recursive template?), to see if any descendents have a value, before copying element
Assuming that by "value" you mean a non whitespace-only text node, you could do simply:
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="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!-- prune branches that do not carry fruit -->
<xsl:template match="*[not(descendant::text())]"/>
</xsl:stylesheet>

Rename tag and remove attribute

I have an XML document (generated by WiX heat) where I want to remove the root element name while removing the attribute. The source tree looks like this
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<DirectoryRef Id="HELP" />
</Fragment>
</Wix>
I figured out how to rename the node, but this doesn't remove the unnecessary attribute xmlns.
<xsl:template match='/wix:Wix'>
<Include>
<xsl:copy-of select="#*|node()"/>
</Include>
</xsl:template>
<!-- Even this template doesn't suppress the attribute xmlns -->
<xsl:template match='#xmlns'/>
I event removed the #*| from the select clause. But this doesn't have any effect.
How can I produce with XSLT 1.0 the following desired output?
<Include>
<Fragment>
<DirectoryRef Id="HELP" />
</Fragment>
</Include>
this doesn't remove the unnecessary attribute xmlns.
xmlnsis not an attribute - it's a namespace, a part of the node's name. If you don't want it in the output, you cannot copy the input nodes that are in a namespace - you must create new nodes instead, for example:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wix="http://schemas.microsoft.com/wix/2006/wi"
exclude-result-prefixes="wix">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/wix:Wix">
<Include>
<xsl:apply-templates/>
</Include>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

Producing default pdf in dita-ot

I have created a plugin and trying to generate my output as a pdf . My build is getting successfully , but my plugin is not running. The output is default pdf. What am I missing ?
this is my build_pdf2w_template/ant file:-
<?xml version="1.0" encoding="UTF-8"?>
<project name="org.dita.pdf2w" default="dita2pdf2w" basedir=".">
<property name="transtype" location="C:\Program Files\dita-ot-2.4"/>
<target name="dita2pdf2w" description="build PDF" depends="pdf"/>
<target name="pdf" description="build PDF">
<ant antfile="C:\Program Files\dita-ot-2.4\plugins\org.dita.pdf2w\build_pdf2w_template.xml">
<property name="args.input" value="D:\AutoCOM-Demo\AutoCOM.ditamap"/>
<property name="args.gen.task.lbl" value="YES"/>
<property name="args.rellinks" value="nofamily"/>
<property name="output.dir" value="C:\"/>
<property name="transtype" value="pdf"/>
</ant>
</target>
</project>
Plugin:-
<?xml version="1.0" encoding="UTF-8"?>
<plugin id="org.dita.pdf2w">
<require plugin="org.dita.pdf2w"/>
<feature extension="dita.conductor.transtype.check" value="pdf2w"/>
<feature extension="dita.transtype.print" value="pdf2w"/>
<feature extension="dita.conductor.target.relative" file="build.xml"/>
</plugin>
Integrator:-
<?xml version="1.0" encoding="UTF-8"?>
<project name="org.dita.pdf2w">
<target name="dita2pdf2w.init">
<property name="customization.dir" location="${dita.plugin.org.dita.pdf2w.dir}/cfg"/>
</target>
<target name="dita2pdf2w" depends="dita2pdf2w.init , dita2pdf2w"/>
</project>
build:-
<?xml version="1.0" encoding="UTF-8"?>
<project>
<import file="build_pdf2w_template.xml"/>
</project>
Your plugin.xml looks good, it references directly the "build.xml" so if you have an "integrator.xml", that is not getting called at all.
In the build.xml the ANT target "dita2pdf2w" has at the end an antcall to itself so that is not good.
Basically your build file should have looked like this:
<project name="org.dita.pdf2w">
<target name="dita2pdf2w.init">
<property location="${dita.plugin.org.dita.pdf2w.dir}/cfg" name="customization.dir"/>
</target>
<target depends="dita2pdf2w.init, dita2pdf2" name="dita2pdf2w"/>
</project>
You can also use Jarno Elovirta's PDF plugin generator to generate a startup customization plugin:
http://dita-generator.elovirta.com/
According to the #RaduCoravu's suggestion I revised your plug-in related files.
[pdf2w/plugin.xml]
<?xml version="1.0" encoding="UTF-8"?>
<plugin id="org.dita.pdf2w">
<feature extension="dita.conductor.transtype.check" value="pdf2w"/>
<feature extension="dita.transtype.print" value="pdf2w"/>
<feature extension="dita.conductor.target.relative" file="integrator.xml"/>
</plugin>
[pdf2w/integrator.xml]
<?xml version="1.0" encoding="UTF-8"?>
<project>
<import file="build.xml"/>
</project>
[pdf2w/build.xml]
<?xml version="1.0" encoding="UTF-8"?>
<project name="org.dita.pdf2w">
<target name="dita2pdf2w.init">
<property location="${dita.plugin.org.dita.pdf2w.dir}/cfg" name="customization.dir"/>
</target>
<target depends="dita2pdf2w.init, dita2pdf2" name="dita2pdf2w"/>
</project>
This will work surely if you properly configure pdf2w/cfg directory.
Following files are one of simple customization examples:
[pdf2w/cfg/catalog.xml]
<?xml version="1.0" encoding="utf-8"?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system">
<!-- Custom XSL code entry.-->
<uri name="cfg:fo/xsl/custom.xsl" uri="fo/xsl/custom.xsl"/>
</catalog>
[pdf2w/cfg/fo/xsl/custom.xsl]
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="2.0">
<xsl:template match="*[contains(#class, ' task/cmd ')]" priority="1">
<fo:block xsl:use-attribute-sets="cmd">
<xsl:call-template name="commonattributes"/>
<xsl:attribute name="color" select="'red'"/>
<xsl:attribute name="font-size" select="'2em'"/>
<xsl:attribute name="font-weight" select="'bold'"/>
<xsl:if test="../#importance='optional'">
<xsl:call-template name="getVariable">
<xsl:with-param name="id" select="'Optional Step'"/>
</xsl:call-template>
<xsl:text> </xsl:text>
</xsl:if>
<xsl:if test="../#importance='required'">
<xsl:call-template name="getVariable">
<xsl:with-param name="id" select="'Required Step'"/>
</xsl:call-template>
<xsl:text> </xsl:text>
</xsl:if>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
</xsl:stylesheet>
[command-line in Windows]
D:\DITA-OT\dita-ot-2.4>bin\dita -i docsrc/samples/sequence.ditamap -f pdf2w -o out
[Result PDF]

How to group a specific number of blocks in an xml based on number of tags

I have a big xml like below and I would like to group a specific number of tags under one block; The expected input and output below will make my question clearer. Any help is greatly appreciated
The input file is
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Root>
<ListABC>
<ABC name="name1" class="class1" age="age1" />
<ABC name="name2" class="class2" age="age2" />
<ABC name="name3" class="class3" age="age3" />
<ABC name="name4" class="class4" age="age4" />
<ABC name="name5" class="class5" age="age5" />
</ListABC>
<ListABC>
<EOF tag1="1" tag2="2" tag3="3"/>
</ListABC>
</Root>
I need to create a tag ListABC after every 2 ABC elements and at the same time, the last ListABC which contains EOF element should not be impacted at all. This is how I need the output
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Root>
<ListABC>
<ABC name="name1" class="class1" age="age1" />
<ABC name="name2" class="class2" age="age2" />
</ListABC>
<ListABC>
<ABC name="name3" class="class3" age="age3" />
<ABC name="name4" class="class4" age="age4" />
</ListABC>
<ListABC>
<ABC name="name5" class="class5" age="age5" />
</ListABC>
<ListABC>
<EOF tag1="1" tag2="2" tag3="3"/>
</ListABC>
</Root>
Thanks much!
How about:
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="/Root">
<xsl:copy>
<xsl:for-each select="ListABC[not (EOF)]/ABC[position() mod 2 = 1]">
<ListABC>
<xsl:copy-of select=". | following-sibling::ABC[1]"/>
</ListABC>
</xsl:for-each>
<xsl:copy-of select="ListABC[EOF]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Counting child notes in an document with multiple namespaces (XBRL)

I am trying (but not succeeding) to count the children in an XBRL document.
I want to know how many schemas, unit, contexts and facts grouped by namespace prefix are used.
Input:
<?xml version="1.0" encoding="utf-8"?>
<xbrl xml:lang="en" xmlns="http://www.xbrl.org/2003/instance"
xmlns:link="http://www.xbrl.org/2003/linkbase"
xmlns:find="http://www.eurofiling.info/xbrl/ext/filing-indicators"
xmlns:xlink="http://www.w3.org/1999/xlink" >
<link:schemaRef xlink:type="simple" xlink:href="http://www.eba.europa.eu/eu/fr/xbrl/crr/fws/corep/its-2013-02/2014-03-31/mod/corep_le_con.xsd" />
<context id="I-2014-9-E">
<entity>
<identifier scheme="http://www.dnb.nl/id">123</identifier>
</entity>
<period>
<instant>2014-09-30</instant>
</period>
</context>
<unit id="u-EUR">
<measure>iso4217:EUR</measure>
</unit>
<unit id="u-pure">
<measure>pure</measure>
</unit>
<find:fIndicators>
<find:filingIndicator contextRef="I-2014-9-E">C_00.01</find:filingIndicator>
</find:fIndicators>
<find:fIndicators>
<find:filingIndicator contextRef="I-2014-9-E">C_26.00</find:filingIndicator>
</find:fIndicators>
<find:fIndicators>
<find:filingIndicator contextRef="I-2014-9-E">C_27.00</find:filingIndicator>
</find:fIndicators>
</xbrl>
Wanted output:
<?xml version="1.0" encoding="utf-8"?>
<XBRLfacts xmlns="http://www.xbrl.org/2003/instance" xmlns:link="http://www.xbrl.org/2003/linkbase">
<linkCount>1</linkCount>
<unitCount>2</unitCount>
<contextCount></contextCount>
<factCount>
<find>3</find>
</factCount>
</XBRLfacts>
XSLT tried:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.xbrl.org/2003/instance" xmlns:link="http://www.xbrl.org/2003/linkbase" >
<xsl:output method="xml" encoding="UTF-8" indent="yes" media-type="text/xml" />
<xsl:template match="/">
<XBRLfacts >
<linkCount>
<xsl:value-of select="//xbrl/link:schemaRef" />
</linkCount>
<unitCount>
<xsl:value-of select="//xbrl/unit" />
</unitCount>
<contextCount>
<xsl:value-of select="//xbrl/context" />
</contextCount>
<!-- something for the facts -->
</XBRLfacts>
</xsl:template>
</xsl:stylesheet>
Output gotten:
<?xml version="1.0" encoding="utf-8"?>
<XBRLfacts xmlns="http://www.xbrl.org/2003/instance" xmlns:link="http://www.xbrl.org/2003/linkbase">
<linkCount></linkCount>
<unitCount></unitCount>
<contextCount></contextCount>
</XBRLfacts>
Any help telling me what I am doing wrong is greatly appreciated.
Thanks.
Paul.
Your source elements are in namespaces. You must assign a prefix to each namespace and use it when addressing the elements in that namespace.
The other thing is that you're not actually counting anything.
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.xbrl.org/2003/instance"
xmlns:xbrl="http://www.xbrl.org/2003/instance"
xmlns:link="http://www.xbrl.org/2003/linkbase"
xmlns:find="http://www.eurofiling.info/xbrl/ext/filing-indicators"
exclude-result-prefixes="xbrl find">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/xbrl:xbrl">
<XBRLfacts>
<linkCount>
<xsl:value-of select="count(link:schemaRef)" />
</linkCount>
<unitCount>
<xsl:value-of select="count(xbrl:unit)" />
</unitCount>
<contextCount>
<xsl:value-of select="count(xbrl:context)" />
</contextCount>
<fIndicatorCount>
<xsl:value-of select="count(find:fIndicators)" />
</fIndicatorCount>
</XBRLfacts>
</xsl:template>
</xsl:stylesheet>
Result:
<?xml version="1.0" encoding="UTF-8"?>
<XBRLfacts xmlns="http://www.xbrl.org/2003/instance" xmlns:link="http://www.xbrl.org/2003/linkbase">
<linkCount>1</linkCount>
<unitCount>2</unitCount>
<contextCount>1</contextCount>
<fIndicatorCount>3</fIndicatorCount>
</XBRLfacts>