I need to concat a number 'N' of the XML in another XML.
For example:
I've this XML
<BOOKS>
<BOOK>
<TITTLE>Lord of the Rings</TITLE>
<AUTHORS>J. R. R. Tolkien</AUTHORS>
<AUTHORS>J. K. Rowling</AUTHORS>
<YEAR>2015</YEAR>
</BOOK>
<BOOK>
<TITTLE>The Hobbit: The Battle of the Five Armies</TITLE>
<AUTHORS>J. R. R. Tolkien</AUTHORS>
<YEAR>2013</YEAR>
</BOOK>
</BOOKS>
and this:
<BOOKS>
<BOOK>
<TITTLE>A Clash of Kings</TITLE>
<AUTHORS>George R. R. Martin</AUTHORS>
<AUTHORS>J. K. Rowling</AUTHORS>
<YEAR>2016</YEAR>
</BOOK>
<BOOK>
<TITTLE>The Hobbit: The Battle of the Five Armies</TITLE>
<AUTHORS>J. R. R. Tolkien</AUTHORS>
<YEAR>2013</YEAR>
</BOOK>
</BOOKS>
I need to generate a new file like this:
<BOOKS>
<BOOK>
<TITTLE>Lord of the Rings</TITLE>
<AUTHORS>J. R. R. Tolkien</AUTHORS>
<AUTHORS>J. K. Rowling</AUTHORS>
<YEAR>2015</YEAR>
</BOOK>
<BOOK>
<TITTLE>The Hobbit: The Battle of the Five Armies</TITLE>
<AUTHORS>J. R. R. Tolkien</AUTHORS>
<YEAR>2013</YEAR>
</BOOK>
<BOOK>
<TITTLE>A Clash of Kings</TITLE>
<AUTHORS>George R. R. Martin</AUTHORS>
<AUTHORS>J. K. Rowling</AUTHORS>
<YEAR>2016</YEAR>
</BOOK>
<BOOK>
<TITTLE>The Hobbit: The Battle of the Five Armies</TITLE>
<AUTHORS>J. R. R. Tolkien</AUTHORS>
<YEAR>2013</YEAR>
</BOOK>
</BOOKS>
The XMLs are in my directory: E:\books. I want to concat all files, for example: If I've two files, the script will concat them, but if I've three or more files, the script will concat also. How do I do it?
In XSLT 2.0 with Saxon it's
<xsl:template name="main">
<BOOKS>
<xsl:sequence select="collection('dir?select=*.xml')/BOOKS/BOOK"/>
</BOOKS>
</xsl:template>
Related
Given the following XML document:
<books>
<book>
<name>The problem of the ages</name>
</book>
<book>
<name>Filtering the tap</name>
</book>
<book>
<name>Legend of Atlantis</name>
</book>
</books>
I want to take at most 2 words from the name of each book. Words can be assumed as being sequences of whitespace-separated characters. Example of output:
<library>
<record>The problem</record>
<record>Filtering the</record>
<record>Legend of</record>
</library>
How would I achieve this using a single XSLT?
Try (in 3.0 with expand-text enabled):
<xsl:template match="book/name">
<record>{tokenize(.) => subsequence(1, 2)}</record>
</xsl:template>
I have a complex XML file structured by book title. Something like this, but with hundreds of books and sometimes many authors per book.
<Book>
<Title>Ken Lum</Title>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
</Author>
</Book>
<Book>
<Title>Shore, Forest and Beyond</Title>
<Author>
<GivenName>Ian M.</GivenName>
<Surname>Thom</Surname>
</Author>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
</Author>
</Book>
What I need to output is an alphabetized list of authors, and then a list of every book they worked on, also alphabetized, something like:
Arnold, Grant — Ken Lum; Shore, Forest and Beyond
Thom, Ian M. — Shore, Forest and Beyond
I have a version of the code working fairly well, but it is very slow, so I'm trying to optimize my approach. I recently learned of the Muenchian method of grouping from another user here and I'm trying to apply that.
The part I'm specifically stuck on right now is getting the list of titles per author. This is what I have right now:
<xsl:key name="books-by-author" match="Book"
use="concat(Author/GivenName, Contributor/Surname)" />
…
<xsl:template match="Author">
…
<xsl:apply-templates mode="ByAuthor" select=
"key('books-by-author',
concat(GivenName, Surname)
)">
<xsl:sort select="Title/TitleText"/>
</xsl:apply-templates>
</template>
But it seems that this is only matching Books where the Author is the first one listed, like:
Arnold, Grant — Ken Lum
Thom, Ian M. — Shore, Forest and Beyond
I figure the xsl:key is only using the first Author element, rather than checking every author. Is it possible to check every Author like that? Or is there a better approach?
I would suggest you look at this way:
XML
<Books>
<Book>
<Title>Ken Lum</Title>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
</Author>
</Book>
<Book>
<Title>Shore, Forest and Beyond</Title>
<Author>
<GivenName>Ian M.</GivenName>
<Surname>Thom</Surname>
</Author>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
</Author>
</Book>
</Books>
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:key name="author" match="Author" use="concat(Surname, ', ', GivenName)" />
<xsl:template match="/Books">
<Authors>
<!-- for each unique author -->
<xsl:for-each select="Book/Author[count(. | key('author', concat(Surname, ', ', GivenName))[1]) = 1]">
<xsl:sort select="Surname"/>
<xsl:sort select="GivenName"/>
<Author>
<!-- author's details-->
<xsl:copy-of select="Surname | GivenName"/>
<!-- list author's books -->
<Books>
<xsl:for-each select="key('author', concat(Surname, ', ', GivenName))/parent::Book">
<xsl:sort select="Title"/>
<xsl:copy-of select="Title"/>
</xsl:for-each>
</Books>
</Author>
</xsl:for-each>
</Authors>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<Authors>
<Author>
<GivenName>Grant</GivenName>
<Surname>Arnold</Surname>
<Books>
<Title>Ken Lum</Title>
<Title>Shore, Forest and Beyond</Title>
</Books>
</Author>
<Author>
<GivenName>Ian M.</GivenName>
<Surname>Thom</Surname>
<Books>
<Title>Shore, Forest and Beyond</Title>
</Books>
</Author>
</Authors>
I need help on regular expression in the below xml code I want to extract values in two tags (title,price) at a time so that my output should look like
Output required:
<title lang="en">Everyday Italian</title>
<price>30.00</price>
<title lang="en">XQuery Kick Start</title>
<price>29.99</price>
<title lang="en">XQuery Kick Start</title>
<price>49.99</price>
<title lang="en">Learning XML</title>
<price>39.95</price>
Right now I am using:
^\s*<title>.*</title>
this code is fetching only <title>
<title lang="en">Everyday Italian</title>
<title lang="en">XQuery Kick Start</title>
<title lang="en">XQuery Kick Start</title>
<title lang="en">Learning XML</title>
How to get two tags at a time? can some one help me
XML:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<price>49.99</price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
Your regex wont match your given xml because you haven't handled attributes for title tag. You can use this regex to get both title and price tags with a single expression:
^\s*<(title|price)[^>]*>(.*)<\/\1>
regex matching price tag example
same regex matching title tag example
Also you can get the tag-name and value using back-reference \1 and \2 to the captured groups.
What is your environment? You can do this easily with grep on a unix-like command line:
grep -E "<(title|price)"
A have a string like '<node attr="some_value">'. How to remove attr="some_value" from this string? I know only attr attribute name and don't know "some_value" value.
P.S. I'm using JavaScript but solution for any language will be great. Thanks in advance.
Try this: Needs jquery.
var xml = '<node attr="some_value">';
var newXml = $(xml).removeAttr('attr');
Using Regexs to play with XML is begging for disaster down the line. I'd use built in Xml functionality to do this.
From w3schools.com
xmlDoc=loadXMLDoc("books.xml");
x=xmlDoc.getElementsByTagName('book');
document.write(x[0].getAttribute('category')); document.write("<br />");
x[0].removeAttribute('category');
document.write(x[0].getAttribute('category'));
Where the XML is
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="children">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="web">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<price>49.99</price>
</book>
<book category="web" cover="paperback">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
classic solution : use String functions, for exemple :
str = str.substring(0,str.indexOf("attr")-1) + ">"
Here is my input XML:
<Books>
<Book>
<BookId>1</BookId>
<Des>Dumm1</Des>
<Comments/>
<OrderDateTime>04/06/2009 12:37</OrderDateTime>
</Book>
<Book>
<BookId>2</BookId>
<Des>Dummy2</Des>
<Comments/>
<OrderDateTime>04/07/2009 12:37</OrderDateTime>
</Book>
<Book>
<BookId>3</BookId>
<Des>Dumm12</Des>
<Comments/>
<OrderDateTime>05/06/2009 12:37</OrderDateTime>
</Book>
<Book>
<BookId>4</BookId>
<Des>Dummy2</Des>
<Comments/>
<OrderDateTime>06/07/2009 12:37</OrderDateTime>
</Book>
</Books>
I pass an XML param and my Input XML is
<BookIDs>
<BookID>2</BookID>
<BookID>3</BookID>
</BookIDs>
My output should be like
<Books>
<Book>
<BookId>2</BookId>
<Des>Dummy2</Des>
<Comments/>
<OrderDateTime>04/07/2009 12:37</OrderDateTime>
</Book>
<Book>
<BookId>3</BookId>
<Des>Dumm12</Des>
<Comments/>
<OrderDateTime>05/06/2009 12:37</OrderDateTime>
</Book>
</Books>
How do I accomplish this using XSLT?
This works in Saxon 6.5.5...
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.1">
<xsl:param name="nodeset">
<BookIDs><BookID>2</BookID><BookID>3</BookID></BookIDs>
</xsl:param>
<xsl:template match="/Books">
<Books>
<xsl:variable name="Copy">
<wrap>
<xsl:copy-of select="Book"/>
</wrap>
</xsl:variable>
<xsl:for-each select="$nodeset/BookIDs/BookID">
<xsl:copy-of select="$Copy/wrap/Book[BookId=current()]"/>
</xsl:for-each>
</Books>
</xsl:template>
</xsl:stylesheet>
A pure XSLT solution will be pretty brittle though. Sub-query predicates didn't work, neither did a key. It is dependent upon the param being recognized as a node-set--which I was unable to achieve with a dynamic value (as opposed to the default in my example), even with exsl:node-set. This is also wasteful in that it copies all the Book elements from the source document.
There may be a better solution in XSLT 2.0. Alternately, if you are initiating your transform with some other language/tool, there may be better approaches available there. Another possibility could include the use of exsl:document to load your source document or params.