【问题标题】:Creat a XSLT in Ant script to change fileref values in a xml file在 Ant 脚本中创建 XSLT 以更改 xml 文件中的过滤值
【发布时间】:2012-08-03 11:41:40
【问题描述】:

我有如下的xml文档,

<chapter xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="chapter1">
<title>First chapter</title>
<section xml:id="section1">
                <imageobject>
                    <image fileref="images/image1.jpg"/>
                </imageobject>
                <imageobject>
                    <image fileref="images/image2.jpg"/>
                </imageobject>
</section>
    <section xml:id="section2" xml:base="../other/section1.xml">  
                    <imageobject>
                        <image fileref="images/image1.jpg"/>
                    </imageobject>
                    <imageobject>
                        <image fileref="images/image2.jpg"/>
                    </imageobject>

<section xml:id="section3" xml:base="../some-other/more/section3.xml">
                    <imageobject>
                        <image fileref="images/image1.jpg"/>
                    </imageobject>
    </section>
    </section>
    <section xml:id="section4" xml:base="../some-other/section4.xml">
                    <imageobject>
                        <image fileref="images/image2.jpg"/>
                    </imageobject>
    </section>
 </chapter>

由于相同的图像名称在不同的部分重复,我正在使用 java 类重命名除第一部分以外的所有图像名称。然后我可以生成重命名的图像名称列表。

现在我还想在上面的 xml 文件中反映这些更改。例如,当我在第 2 节中将“image1.jpg”重命名为“aaa.jpg”时,我需要通过生成具有新重命名图像名称的新 xml 来反映初始 xml 中的更改。

为此,我正在使用使用 XSLT 1.0 的 Ant 脚本,并将我的第一个 xml 和重命名的图像列表作为输入,并使用新的 fileref 值生成一个新的 xml 文档。如何制作 XSLT 并在我的 Ant 脚本中使用它。

这是我新重命名的图像列表。

<Imagedata>
  <section>
    <sectionID>section2</sectionID>
    <relativepath>images/aaa.jpg</relativepath>
    <relativepath>images/bbb.jpg</relativepath>
  </section>
  <section>
    <sectionID>section3</sectionID>
    <relativepath>images/ccc.jpg</relativepath>
  </section>
   <section>
    <sectionID>section4</sectionID>
    <relativepath>images/ddd.jpg</relativepath>
  </section>
</Imagedata>

我的新最终 xml 将类似于,

<chapter xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="chapter1">
    <title>First chapter</title>
    <section xml:id="section1">
                    <imageobject>
                        <image fileref="images/image1.jpg"/>
                    </imageobject>
                    <imageobject>
                        <image fileref="images/image2.jpg"/>
                    </imageobject>
    </section>
        <section xml:id="section2" xml:base="../other/section1.xml">  
                        <imageobject>
                            <image fileref="images/aaa.jpg"/>
                        </imageobject>
                        <imageobject>
                            <image fileref="images/bbb.jpg"/>
                        </imageobject>

    <section xml:id="section3" xml:base="../some-other/more/section3.xml">
                        <imageobject>
                            <image fileref="images/ccc.jpg"/>
                        </imageobject>
        </section>
        </section>
        <section xml:id="section4" xml:base="../some-other/section4.xml">
                        <imageobject>
                            <image fileref="images/ddd.jpg"/>
                        </imageobject>
        </section>
     </chapter>

谢谢你..!!

【问题讨论】:

    标签: xml xslt ant xslt-1.0


    【解决方案1】:

    只是为了快速演示,我已将 Imagedata 文档放入下面显示的样式表中的一个变量中。在实际使用中,会传入一个参数,即图像数据文档的 URI,像这样...

    <xsl:param name="ImageDataURI" />
    <xsl:variable name="ImageData" select="document($ImageDataURI)" />
    

    除此之外,这个 XSLT 1.0 样式表...

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:variable name="ImageData">
    <Imagedata>
      <section>
        <sectionID>section2</sectionID>
        <relativepath>images/aaa.jpg</relativepath>
        <relativepath>images/bbb.jpg</relativepath>
      </section>
      <section>
        <sectionID>section3</sectionID>
        <relativepath>images/ccc.jpg</relativepath>
      </section>
       <section>
        <sectionID>section4</sectionID>
        <relativepath>images/ddd.jpg</relativepath>
      </section>
    </Imagedata>
    </xsl:variable>
    
    <xsl:template match="@*|node()">
      <xsl:copy>
       <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </xsl:template>
    
    <xsl:template match="image/@fileref">
      <xsl:attribute name="fileref">
        <xsl:value-of select="
        (msxsl:node-set($ImageData)/Imagedata/section/
        sectionID[.=current()/../../../self::section/@xml:id]/
        following-sibling::relativepath[
         count( current()/../../preceding-sibling::imageobject) + 1
          ] | .)[1]"/>
      </xsl:attribute>  
    </xsl:template>
    
    </xsl:stylesheet>
    

    ...会将您提供的输入文档转换为预期的输出文档。

    说明

    考虑最后一个模板中的 value-of 表达式。从匹配的 fileref 属性开始,我们向上导航,直到到达 section 并获取它的 id。这是由表达式给出的...

    current()/../../../self::section/@xml:id
    

    然后我们获取查找数据并找到 sectionID 。这是由表达式给出的......

    msxsl:node-set($ImageData)/Imagedata/section/sectionID
    

    我们需要按部分名称交叉链接这些部分。我们通过对 sectionID 应用一个谓词来实现这一点,该谓词的值必须是焦点项目的部分值。谓词在这里...

    [.=current()/../../../self::section/@xml:id]
    

    现在我们找到了正确的查找部分,我们需要通过文档部分中焦点项目的当前位置来索引它。我们通过计算前面的兄弟姐妹并加一来计算我们的位置,就像这样......

    count( current()/../../preceding-sibling::imageobject) + 1
    

    因此查找替换节点(如果存在)由...给出...

    msxsl:node-set($ImageData)/Imagedata/section/
    sectionID[.=current()/../../../self::section/@xml:id]/
    following-sibling::relativepath[
     count( current()/../../preceding-sibling::imageobject) + 1
    

    按顺序进行替换时,这一切都很好,但是在某些情况下没有共同响应的查找。在这种情况下,我们的属性需要保留其原始值。我们通过以下形式的表达式来实现这一点 ...

    ( $something | .)[1]
    

    如果 $something 不存在(意思是它的值是空序列),那么上面的表达式只返回焦点项目。如果确实存在,则返回 $something 的第一项或焦点项。通常联合运算符连接两个序列、重复数据删除和按文档顺序排序。但是这两个操作数来自不同的文档,因此没有排序或重复数据删除。因此,表达式在存在时返回替换节点,如果不存在则返回焦点项。

    【讨论】:

    • ,非常感谢您的回复和很好的解释。您是否尝试过使用我提供的 xml 文档,它是否成功生成了预期的输出?我收到一条错误消息,提示“xmlXPathCompOpEval:未找到函数节点集 XPath 错误:未注册函数运行时错误:文件 sean.xsl 第 34 行元素值 - XPath 评估未返回结果。”这里 sean.xsl 是你的 xslt 文档..我正在使用 xsltproc..谢谢..
    • 如果你想使用node-set(),它属于哪个命名空间取决于你的XSLT处理器。尝试 xmlns:exsl="exslt.org/common 而不是给定的微软。
    • ,,我正在使用 xsltproc 处理器。它仍然给出一个错误函数 node-set not found。 xsltproc 处理器的命名空间是什么??
    • 我使用了 xmlns:exsl="exslt.org/common" 并生成了一个类似于我的主 xml 文档的 xml 输出。我尝试进行一些修改,但无法生成预期的输出。我对 XSLT 很陌生。请告诉我我可能在哪里遗漏了一些东西。在我的输出 xml 中,我想从 section2 而不是 section1 进行更改。有什么方法可以在不使用 node-set() 函数的情况下生成输出?提前谢谢..
    • 我提供的样式表确实对第 2 节而不是第 1 节进行了更改。这已在 www.xmlper.com 上进行了测试,并且效果很好。如果没有看到它,我无法判断您的样式表有什么问题。请接受我的回答(单击对勾符号),并使用您的确切样式表、示例输入和预期输出发布一个新问题。
    猜你喜欢
    • 2016-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多