【问题标题】:XSLT transformation of child nodes子节点的 XSLT 转换
【发布时间】:2013-11-25 18:19:54
【问题描述】:

我正在使用 boost 序列化来实现持久性,并且由于该库不支持保存到旧版本的存档/数据结构的想法,但我想给 XSLT 和 XPath 一个转换的机会根据需要从新版本到旧版本。

我已经完成了大约一半,但似乎无法完成(这也是我第一次尝试 XSLT 和 XPath/XQuery,所以请原谅任何明显的错误)。

这是我的起始 XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="7">
<tester class_id="0" tracking_level="0" version="0">
    <count>2</count>
    <item_version>0</item_version>
    <item class_id="2" class_name="CLASS_D" tracking_level="0" version="0">
        <A class_id="1" tracking_level="1" version="0" object_id="_0">
            <pimpl class_id="3" tracking_level="1" version="0" object_id="_1">
                <b>1</b>
            </pimpl>
        </A>
        <pimpl class_id="4" tracking_level="1" version="0" object_id="_2">
            <c>2</c>
        </pimpl>
    </item>
    <item class_id="5" class_name="CLASS_E" tracking_level="0" version="0">
        <A object_id="_3">
            <pimpl class_id_reference="3" object_id="_4">
                <b>1</b>
            </pimpl>
        </A>
        <pimpl class_id="6" tracking_level="1" version="0" object_id="_5">
            <f>2</f>
        </pimpl>
    </item>
</tester>
</boost_serialization>

我想要做的是将具有属性 class_name="CLASS_E" 的项目转换为具有 class_name="CLASS_D" 的项目,但我需要单独保留 object_id 属性。

这就是我想要的:

<?xml version="1.0" encoding="utf-8"?>
<boost_serialization signature="serialization::archive" version="7">
  <tester class_id="0" tracking_level="0" version="0">
    <count>2</count>
    <item_version>0</item_version>
    <item class_id="2" class_name="CLASS_D" tracking_level="0" version="0">
      <A class_id="1" tracking_level="1" version="0" object_id="_0">
        <pimpl class_id="3" tracking_level="1" version="0" object_id="_1">
          <b>1</b>
        </pimpl>
      </A>
      <pimpl class_id="4" tracking_level="1" version="0" object_id="_2">
        <c>2</c>
      </pimpl>
    </item>
    <item class_name="CLASS_D" class_id="2" tracking_level="0" version="0">
      <A object_id="_3">
        <pimpl class_id_reference="3" object_id="_4">
          <b>1</b>
        </pimpl>
      </A>
      <pimpl class_id="4" tracking_level="1" version="0" object_id="_5">
        <c>2</c>
      </pimpl>
    </item>
  </tester>
</boost_serialization>

这是我目前的模板:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" omit-xml-declaration="no" encoding="UTF-8" indent="yes"/>

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

  <!-- replace attribute class_name value with another-->
  <!-- replace attribute class_id value with another-->
  <!-- only on this node!-->
  <!-- could call another template to change more nested things-->
  <xsl:template match="item/@class_name[. =  'CLASS_E']">
    <xsl:attribute name="class_name">CLASS_D</xsl:attribute>
    <xsl:attribute name="class_id">2</xsl:attribute>
  </xsl:template>

</xsl:stylesheet>

我不确定如何继续编辑与此行匹配的项目的子节点: 因为我需要将“f”节点更改为“c”并将 pimpl “class_id”从 6 更改为 4

提前致谢

【问题讨论】:

    标签: xml xslt xpath boost-serialization


    【解决方案1】:

    你刚才匹配的item是一个属性,所以没有子节点!父节点将与身份模板匹配,因此要“继续”编辑,只需有一个与您希望匹配的 class_id 属性匹配的模板,但在相关 上包含一个匹配项xpath 表达式中的项目

    例如,要更改 pimpl 元素的 class_id,请添加此模板

     <xsl:template match="item[@class_name =  'CLASS_E']/pimpl/@class_id">
        <xsl:attribute name="class_id">4</xsl:attribute>
     </xsl:template>
    

    要更改 f 元素,请添加此模板

    <xsl:template match="item[@class_name =  'CLASS_E']/pimpl/f">
       <c>
          <xsl:apply-templates select="@*|node()"/>
       </c>
    </xsl:template>
    

    请记住,匹配适用于输入文档,因此在输出文档中您已将“CLASS_E”更改为“CLASS_D”并不重要。

    请注意,您当前的模板与 class_name 属性匹配可能存在问题。在此,您将用两个属性替换它,包括已经存在的 class_id 属性。 XSLT 将替换输出树中已经输出同名的属性。这意味着如果您的 XML 实际上看起来像这样......

    <item class_name="CLASS_E" class_id="5"  tracking_level="0" version="0">
    

    那么它的输出实际上会是这个

    <item class_name="CLASS_D" class_id="5" tracking_level="0" version="0">
    

    这是因为身份模板将在您的模板匹配 class_name 之后匹配 class_id 属性,因此将替换 class_id 属性它当前匹配的那个。

    但长话短说,试试这个 XSLT .....

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" omit-xml-declaration="no" encoding="UTF-8" indent="yes"/>
    
      <!-- identity-->
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="item/@class_name[. =  'CLASS_E']">
        <xsl:attribute name="class_name">CLASS_D</xsl:attribute>
      </xsl:template>
    
      <xsl:template match="item[@class_name =  'CLASS_E']/@class_id">
        <xsl:attribute name="class_id">2</xsl:attribute>
      </xsl:template>
    
      <xsl:template match="item[@class_name =  'CLASS_E']/pimpl/@class_id">
         <xsl:attribute name="class_id">4</xsl:attribute>
      </xsl:template>
    
      <xsl:template match="item[@class_name =  'CLASS_E']/pimpl/f">
         <c>
            <xsl:apply-templates select="@*|node()"/>
         </c>
      </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

    • 非常感谢您的详细回复。它帮助我解决了很多问题。
    猜你喜欢
    • 2017-01-13
    • 1970-01-01
    • 2017-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-27
    相关资源
    最近更新 更多