XML to XML conversion with XSLT (Add, delete, modify)

我怕爱的太早我们不能终老 提交于 2020-01-03 04:14:19

问题


I'm trying to convert from one XML (XHTML) file to another one with XSLT. I have to add some new elements and attributes, remove some elements and attributes as well as update the value of some existing attributes. So for with the valuable help given in this forum, I'm able to do many tasks as per the answer of my previous question: XML to XML with XSLT- Add, Remove, Modify Elements and Attributes but the problem arises when the elements have the same name and one same attribute. At that point I'm unable to distinguish it for modification. For Example: I have two scripts of type="t/j" after the div tag where id="123" and one script of type="t/j" inside the head tag. I have to remove the script element where src="abc.js", only when it appears after the div tag (not inside the head tag) and change the value of xyz.js to lmn.js. I have made comments in my source and desired file regarding the amendments. For eliminating the onClick event I'm passing a template match which does nothing using @onClick and it is removing the onClick event from everywhere as per the requirement. However, when I apply the same technique for removing the 'span' tag from a specific location (commented in the source file) then it not only removes from there but from all the other places also where I don't want to. Please find my XML files below-

Source file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-type" content="text/html;  charset=utf-8" />
<script type="t/j" src="abc.js"></script>
</head>

<body>
<div id="o">
<div id="m">
<div id="nD">
<p id="nT">
Part 1</p>
</div>

<div class="TF" id="123">
<!--CHANGE THE VALUE OF XYZ.JS TO LMN.JS-->
<script type="t/j" src="xyz.js"></script>
<!--REMOVE THIS SCRIPT-->
<script type="t/j" src="abc.js"></script>
<div class="iD">
<img alt="" src="ic.gif" />
<span class="iDe">ABC</span><br/>
<div class="iDev">
<div id="ta12" class="bl" style="dis:bl"></div>

<div class="q">
<br/><br/>
<!--TO REMOVE SPAN TAG FROM HERE-->
<div id="ta12" class="bl" style="dis:bl">1<span style="color: #000000;"> XYZ</span> </div>
<!--REMOVE ONCLICK EVENT -->
<br/>T <input type="radio" name="op12" id="t12" onclick="getFeedback()"/> 
F <input type="radio" name="op12" id="f12" onclick="getFeedback()"/>
<div>C </div>
<div>In </div>

<div>
<div></div>
</div>
</div>

</div>
</div>
</div>

</div>
</div>
</body></html>

Desired file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;  charset=utf-8" />
<script type="t/j" src="abc.js"></script>
</head>

<script type="t/j" src="pqr.js"></script>
<script type="t/j" src="stu.js"></script>

<body onload="load()" onunload="unload()">
<div id="o">
<div id="m">
<div id="nD">
<p id="nT">
Part 1</p></div>

<div class="QT" id="456">
<script type="t/j" src="lmn.js"></script>
<form name="form1" id="q8" action="js:cal();">
<div class="iD">
<img alt="" src="ic.gif" />
<span class="iDe">ABC</span>
<div class="iDev">
<!--ADD THIS DIV TAG-->
<div class="pa" value="10"></div>

<div class="q">
<div id="ta8" class="bl" style="dis:bl">XYZ 
</div><br/>
<input type="radio" name="ke8" value="0" />
<div id="tab8" class="bl" style="dis:bl">T 
</div>
<input type="radio" name="ke8" value="1" />
<div id="tab8" class="bl" style="dis:bl">F 
</div>
</div>
<br/><input type="submit" name="sub" value="Done"/>
</div></div>
</form>
</div>
</div>
</div>

</body></html>

I'm using XSLT 1.0. So for as per suggestions and some modifications (although it differs at some places like where id="1") my XSLT looks like: UPDATED

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xhtml="http://www.w3.org/1999/xhtml"
 xmlns="http://www.w3.org/1999/xhtml"
 exclude-result-prefixes="xhtml">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:strip-space elements="*" />

<xsl:template match="@*|node()">
 <xsl:copy>
  <xsl:apply-templates select="@*|node()"/>
 </xsl:copy>
</xsl:template>

<xsl:template match="xhtml:body">
<script type="t/j" src="pqr.js"></script>
<script type="t/j" src="stu.js"></script>
<body onload="loadPage()" onunload="unloadPage()">
  <xsl:apply-templates select="@*|node()"/>
</body>
</xsl:template>
<xsl:template match="xhtml:div[@id='123']/@class">
  <xsl:attribute name="class">QT</xsl:attribute>
   <xsl:attribute name="id">456</xsl:attribute> 
</xsl:template>
<xsl:template match="xhtml:script[@src='xyz.js']">
 <xsl:copy>
  <xsl:apply-templates select="@*[not(@src)]" />
  <xsl:attribute name="src">lmn.js</xsl:attribute>
  <xsl:apply-templates select="node()" />
 </xsl:copy>
</xsl:template>
<xsl:template match="xhtml:body//xhtml:script[@src='abc.js']" />

<xsl:template match="xhtml:div[@class='iD']">
  <form name="form">
   <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
   <xsl:apply-templates select="following-sibling::xhtml:div[1]" mode="inside-form"/>
   <br/><input type="submit" name="sub" value="Done"/> 
  </form>
</xsl:template>
<xsl:template match="xhtml:div[@id='ta12']">
  <xsl:attribute name="class">pa</xsl:attribute>
  <xsl:attribute name="value">10</xsl:attribute>
</xsl:template>

<xsl:template match="xhtml:div[@class='iDev']">
   <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
     <div id="ta8" class="bl" style="dis:bl">XYZ</div>
<br/>
   <input type="radio" name="ke8" value="0" />
<div id="tab8" class="bl" style="dis:bl">T</div>
   <input type="radio" name="ke8" value="1" />
<div id="tab8" class="bl" style="dis:bl">F</div>
</xsl:template>

</xsl:stylesheet>

THE OUTPUT WHICH I'M GETTING-

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-type" content="text/html;  charset=utf-8"/>
<script type="t/j" src="abc.js" xml:space="preserve"/>
</head>
<script type="t/j" src="pqr.js"/>
<script type="t/j" src="stu.js"/>
<body onload="loadPage()" onunload="unloadPage()">
<div id="o">
<div id="m">
<div id="nD">
<p id="nT">
Part 1</p>
</div>
<!--VALUE OF CLASS HAS CHANGED BUT NOT ID-->
<div class="QT" id="123">
<script type="t/j" src="lmn.js" xml:space="preserve"/>
<form name="form">
<div class="iD">
<img alt="" src="ic.gif"/>
<span class="iDe">ABC</span>
<br clear="none"/>
<!--DIV TAG WITH CLASS=IDEV IS MISSING-->
<div class="pa" value="10">
<div class="q">
<!--BR HAVE APPEARED WITH ATTRIBUTE CLEAR-->
<br clear="none"/>
<br clear="none"/>
<!--INPUT TAGS HAVE APPEARED TWICE-->
<br clear="none"/>T <input type="radio" name="op12" id="t12" onclick="getFeedback()"/> 
F <input type="radio" name="op12" id="f12" onclick="getFeedback()"/>
<div>C </div>
<div>In </div>
<div>
<div/>
</div>
</div>
</div>
<div id="ta8" class="bl" style="dis:bl">XYZ</div>
<br/>
<input type="radio" name="ke8" value="0"/>
<div id="tab8" class="bl" style="dis:bl">T</div>
<input type="radio" name="ke8" value="1"/>
<div id="tab8" class="bl" style="dis:bl">F</div>
</div>
<br/>
<input type="submit" name="sub" value="Done"/>
</form>
</div>
</div>
</div>
</body>
</html>

Thanking you!


回答1:


In 90% of XSLT questions, the greatest challenge, is not the technical aspect of the question, but rather how to articulate the rules of transformation in the form of match pattern and corresponding output. Rather than give you a style-sheet, I'll give you a pattern & output view of your question. You should be able to make a style-sheet from this. There are no special techniques involved.

Comparing your input and output documents, I would describe the rules of transformation as follows.

  1. Copy the input document to the output with the following exceptions.
  2. Precede the <body> with the following literals

    <script type="t/j" src="pqr.js" />
    <script type="t/j" src="pqr.js" />
    
  3. Append to the <body> element attributes @onload="load()" and @onunload="unload()".

  4. For any <div> elements that have @id=123, change @class to QT and id to 456.
  5. For any <script> elements change @src="xyz.js" to "lmn.js".
  6. For any <script> elements in the body with @src="abc.js", delete.
  7. Wrap any <div> elements that have @class="iD" in a <form> and just before the close of the form, include the following literals

    <br/><input type="submit" name="sub" value="Done"/>
    
  8. Replace any <div> elements with @id="ta12" with this replacement:

    <div id="pa" value="10" />
    
  9. Copy any <div class="iDev">, except replace its children with the following literals

    <div id="ta8" class="bl" style="dis:bl">XYZ</div>
    <br/>
    <input type="radio" name="ke8" value="0" />
    <div id="tab8" class="bl" style="dis:bl">T</div>
    <input type="radio" name="ke8" value="1" />
    <div id="tab8" class="bl" style="dis:bl">F</div>
    

Update

The OP has asked for a template for point 5. So here it is. This is a general solution on how to copy a node, just changing one attribute ...

<xsl:template match="xhtml:script[@src='xyz.js']">
 <xsl:copy>
  <xsl:apply-templates select="@*[not(@src)]" />
  <xsl:attribute name="src">lmn.js</xsl:attribute>
  <xsl:apply-templates select="node()" />
 </xsl:copy>
</xsl:template>

If you didn't mind having a less general solution and could afford to assume that the script element would have no children and only one other attribute @type="t/j" , you could for example, use a more concise and specific template like so (but I would not recommend it - I am just laying out your options ...

<xsl:template match="xhtml:script[@src='xyz.js']">
 <xhtml:script type="t/j" src="lmn.js" />
</xsl:template>

And for point 6 it is ...

<xsl:template match="xhtml:body//xhtml:script[@src='abc.js']" />


来源:https://stackoverflow.com/questions/11606596/xml-to-xml-conversion-with-xslt-add-delete-modify

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!