0

我有如下的 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 文件中反映这些变化。例如,当我在 section2 中将“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>

谢谢..!!

4

1 回答 1

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 的第一项或焦点项。通常联合运算符连接两个序列、重复数据删除和按文档顺序排序。但是这两个操作数来自不同的文档,因此没有排序或重复数据删除。因此,表达式在存在时返回替换节点,如果不存在则返回焦点项。

于 2012-08-03T13:37:44.730 回答