I have the following structure of xml data to transform:
<root>
<main1>
<page>
<text-body>
<title>K1</title>
<subtitle>Text</subtitle>
</text-body>
<text-body>
<title>Text</title>
<subtitel>Text</subtitel>
</text-body>
<text-body>
<title>Text</title>
<subtitel>Text</subtitel>
</text-body>
</page>
<page>
<text-body>
<title>K2</title>
<subtitel>Text</subtitel>
</text-body>
<text-body>
<title>Text</title>
<subtitel>Text</subtitel>
</text-body>
</page>
<page>
<text-body>
<title>K3</title>
<subtitel>Text</subtitel>
</text-body>
<text-body>
<title>Text</title>
<subtitel>Text</subtitel>
</text-body>
</page>
</main1>
<main2>
<text-body>
<title>B</title>
<subtitle>B</subtitle>
<body>B</body>
</text-body>
<text-body>
<title>C</title>
<subtitle>C</subtitle>
<body>C</body>
</text-body>
<text-body>
<title>D</title>
<subtitle>D</subtitle>
<body>D</body>
</text-body>
</main2>
</root>
And I need to replace the data in main1/text-body with titles K1, K2, K3 with the data in main2/text-body, but keep the other text-body elements in main1. The output should look like this:
<root>
<main1>
<page>
<text-body>
<title>B</title>
<subtitle>B</subtitle>
<body>B</body>
</text-body>
<text-body>
<title>Text</title>
<subtitel>Text</subtitel>
</text-body>
<text-body>
<title>Text</title>
<subtitel>Text</subtitel>
</text-body>
</page>
<page>
<text-body>
<title>C</title>
<subtitle>C</subtitle>
<body>C</body>
</text-body>
<text-body>
<title>Text</title>
<subtitel>Text</subtitel>
</text-body>
</page>
<page>
<text-body>
<title>D</title>
<subtitle>D</subtitle>
<body>D</body>
</text-body>
<text-body>
<title>Text</title>
<subtitel>Text</subtitel>
</text-body>
</page>
</main1>
<main2>
<text-body>
<title>B</title>
<subtitle>B</subtitle>
<body>B</body>
</text-body>
<text-body>
<title>C</title>
<subtitle>C</subtitle>
<body>C</body>
</text-body>
<text-body>
<title>D</title>
<subtitle>D</subtitle>
<body>D</body>
</text-body>
</main2>
</root>
I have the following xsl-code:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="main1/page/text-body">
<xsl:param name="count" select="title/substring(.,2,1)"/>
<xsl:if test="title/substring(.,1,1)='K'">
<xsl:copy-of select="/root/main2/text-body[$count]"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I try to select the number in the title and to check, if there is a K in the text. But it doesn´t work. And I have no idea how to keep the other text-body elements. Here is the current output:
<main1>
<page>
<text-body>
<title>B</title>
<subtitle>B</subtitle>
<body>B</body>
</text-body><text-body>
<title>C</title>
<subtitle>C</subtitle>
<body>C</body>
</text-body><text-body>
<title>D</title>
<subtitle>D</subtitle>
<body>D</body>
</text-body>
</page>
<page>
<text-body>
<title>B</title>
<subtitle>B</subtitle>
<body>B</body>
</text-body><text-body>
<title>C</title>
<subtitle>C</subtitle>
<body>C</body>
</text-body><text-body>
<title>D</title>
<subtitle>D</subtitle>
<body>D</body>
</text-body>
</page>
<page>
<text-body>
<title>B</title>
<subtitle>B</subtitle>
<body>B</body>
</text-body><text-body>
<title>C</title>
<subtitle>C</subtitle>
<body>C</body>
</text-body><text-body>
<title>D</title>
<subtitle>D</subtitle>
<body>D</body>
</text-body>
</page>
</main1>
<main2>
<text-body>
<title>B</title>
<subtitle>B</subtitle>
<body>B</body>
</text-body>
<text-body>
<title>C</title>
<subtitle>C</subtitle>
<body>C</body>
</text-body>
<text-body>
<title>D</title>
<subtitle>D</subtitle>
<body>D</body>
</text-body>
</main2>
</root>
Please help!
Use a predicate to match only the text-body
elements you really want to exchange. As you're using XSLT 2.0, you can use a regular expression in the predicate:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="main1/page/text-body[matches(title,'^K\d+$')]">
<xsl:variable name="count" select="xs:integer(title/substring(.,2))"/>
<xsl:copy-of select="/root/main2/text-body[$count]"/>
</xsl:template>
</xsl:stylesheet>
The main problem is that your count parameter is set to be a string, but if you want to use in as an index, it should be a number, so you will need to do this
<xsl:copy-of select="/root/main2/text-body[number($count)]"/>
Also, you probably don't want to use an xsl:if here, because with your current template, it will not output text-body elements when the if condition is false. You should actually move the test to be part of the template match.
<xsl:template match="main1/page/text-body[title/substring(.,1,1)='K']">
Here's the full XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="main1/page/text-body[title/substring(.,1,1)='K']">
<xsl:param name="count" select="title/substring(.,2,1)"/>
<xsl:copy-of select="/root/main2/text-body[number($count)]"/>
</xsl:template>
</xsl:stylesheet>
This should produce your expected output.
If your are interested in a different approach, you could chose to define an xsl:key to look up the main2/text-body elements
<xsl:key name="main2"
match="main2/text-body"
use="concat('K', count(preceding-sibling::text-body) + 1)" />
That way, you can remove the need for substring by using the following template for matching the main1/page/text-body elements instead
<xsl:template match="main1/page/text-body[key('main2', title)]">
<xsl:copy-of select="key('main2', title)"/>
</xsl:template>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.