使用 XSLT 将 XML 转换为 XML(添加、删除、修改)

Posted

技术标签:

【中文标题】使用 XSLT 将 XML 转换为 XML(添加、删除、修改)【英文标题】:XML to XML conversion with XSLT (Add, delete, modify) 【发布时间】:2012-07-21 08:07:27 【问题描述】:

我正在尝试使用 XSLT 从一个 XML (Xhtml) 文件转换为另一个。我必须添加一些新元素和属性,删除一些元素和属性以及更新一些现有属性的值。因此,在本论坛提供的宝贵帮助下,我能够按照我之前的问题的答案完成许多任务:XML to XML with XSLT- Add, Remove, Modify Elements and Attributes 但是当元素具有相同的名称和一个相同的属性时就会出现问题。那时我无法区分它以进行修改。 例如:我在 id="123" 的 div 标签后面有两个 type="t/j" 的脚本,在 head 标签内有一个 type="t/j" 的脚本。我必须删除 src="abc.js" 的脚本元素,仅当它出现在 div 标签之后(不在 head 标签内)并将 xyz.js 的值更改为 lmn.js。 我已经在我的源代码和所需文件中制作了有关修改的 cmets。为了消除 onClick 事件,我传递了一个模板匹配,它使用 @onClick 什么都不做,它根据要求从任何地方删除 onClick 事件。 但是,当我应用相同的技术从特定位置(在源文件中注释)删除“跨度”标签时,它不仅会从那里删除,还会从我不想删除的所有其他地方删除。请在下面找到我的 XML 文件-

源文件:

<?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  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>

所需文件:

<?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  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>

我正在使用 XSLT 1.0。因此,根据建议和一些修改(尽管在 id="1" 等某些地方有所不同),我的 XSLT 看起来像: 更新

<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>

我得到的输出-

<?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  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>

谢谢!

【问题讨论】:

请编辑问题并提供一个尽可能少但完整的示例——而不是真正的 XML 文档。还提供确切的所需结果并解释转换规则。这是为了使问题更容易理解,并增加任何希望花时间阅读、理解和回答的读者的机会。我相信一个不超过 20 行缩进的 XML 文档可以用来表达这个问题。 感谢您的回复。我一定会记住它,实际上我的原始文件很长,所以我试着让它很短,只包含一个部分,但从现在开始我会让它更短。 【参考方案1】:

在 90% 的 XSLT 问题中,最大的挑战不是问题的技术方面,而是如何以匹配模式和相应输出的形式表达转换规则。我不会给你一个样式表,而是给你一个问题的模式和输出视图。您应该能够从中制作样式表。不涉及特殊技术。

比较你的输入和输出文件,我将转换规则描述如下。

    将输入文档复制到输出,但以下情况除外。

    前面加上以下文字
    <script type="t/j" src="pqr.js" />
    <script type="t/j" src="pqr.js" />
    

    附加到

    元素属性 @onload="load()" 和 @onunload="unload()"。 对于任何具有@id=123 的 元素,将@class 更改为QT,将id 更改为456。 对于任何 对于任何

    将任何具有@class="iD" 的

    元素包装在
    中并且在表单关闭之前,包括以下文字
    <br/><input type="submit" name="sub" value="Done"/>
    

    用 @id="ta12" 替换任何

    元素:
    <div id="pa" value="10" />
    

    复制任何

    ,但将其子项替换为以下文字
    <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>
    

    更新

    OP 要求提供第 5 点的模板。所以就在这里。这是关于如何复制节点的通用解决方案,只需更改一个属性...

    <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>
    

    如果您不介意使用不太通用的解决方案并且可以假设脚本元素没有子元素并且只有一个其他属性 @type="t/j" ,例如,您可以使用更简洁的和像这样的特定模板(但我不推荐它 - 我只是在列出你的选择......

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

    第 6 点是……

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

    【讨论】:

    再次感谢您提供如此详细的回答。对于你提到的第五点,我写了 我真的很感谢你。非常感谢这么好的答案。 :) 我现在将实施这个答案来修改我的整个文件。再次感谢您的帮助。 我尝试按照这些步骤编写 XSLT 文件,然后转换输入文件。几乎所有事情都完成了,除了与所需输出的差异很小。请在更新后的问题中找到我的 XSLT 和输出,并建议我需要做哪些更改。谢谢! 而不是这个 在 Div class="iDev" 我试图只复制那些我需要的节点,但该方法没有'不起作用,如果我删除这个 @*|node() 然后它会根据要求显示一次输入标签,但它只复制我通过的那些文字。请在问题中找到我更新的 XSLT,并告诉我需要进行哪些修改。我会非常感谢你的帮助。 :) 如果我删除这个 @*|node() 并且不复制 中的所有节点,那么它也会更正 标签。我认为我在替换孩子时没有正确地做这些事情。请改正。谢谢你!。

以上是关于使用 XSLT 将 XML 转换为 XML(添加、删除、修改)的主要内容,如果未能解决你的问题,请参考以下文章

使用带有条件的 XSLT 将 XML 转换为 XML

WSO2 Enterprise Integrator 6.6.0 使用 XSLT 将 XML 响应转换为 Json

使用 XSLT 将 XML 转换为 XML 删除前导空格和零

使用 XSLT 将 XML 元素转换为 XML 属性

如何使用 XSLT 将 JSON 转换为 XML?

使用 XSLT 将 XML 转换为 JSON