XSLT中的双斜线

den*_*nok 1 xml xslt xpath

我有一个样式表,它包含两个文件,一个来自工程库,另一个来自文档库,然后将它们合并以创建一些DITA文件(进一步处理)。最近,我试图将文档文件的内容分为通用文件和特定文件。因此,我的合并现在是一个包含两个文档文件的工程文件。

通用文件是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<messages xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <message id="IDENT_STRING">
    ....
  </message>
</messages>
Run Code Online (Sandbox Code Playgroud)

特定文件具有指向通用文件的ENTITY标签:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE messages [
<!ENTITY generic-file SYSTEM "generic-file.xml">
]>
<messages> &generic-file; <!-- specific-file -->
  <message id="IDENT_STRING2">
    ....
  </message>
</messages>
Run Code Online (Sandbox Code Playgroud)

选择是这样写的:

<xsl:copy-of select="$docid/message[@id=$id]/doc/explanation/text()"/>
Run Code Online (Sandbox Code Playgroud)

这只会从特定文件中获取内容。直到我将select更改为两个斜杠后,我的样式表才能正常工作。这是正确的版本:

<xsl:copy-of select="$docid//message[@id=$id]/doc/explanation/text()"/>
Run Code Online (Sandbox Code Playgroud)

我对社区的问题是1)为什么第二种语法正确?和2)我将如何更快地找到它?

Fel*_*lan 5

这是/ x / y // z是xpath的一个很好的信息来源,http://www.w3.org/TR/xpath/#location-paths

在缩写语法部分://是/ descendant-or-self :: node()/的缩写。例如,// para是/ descendant-or-self :: node()/ child :: para的缩写,因此将选择文档中的任何para元素(即使是文档元素的para元素也将由/选择/ para,因为文档元素节点是根节点的子节点);div // para是div / descendant-or-self :: node()/ child :: para的缩写,因此将选择div子级的所有para后代。

//是在xpath的开始还是中间,其含义是相同的。

就学习这些东西而言,对我来说,我必须构造小型的人工xml或我尝试转换的xml简化外壳,然后运行xslt。在Visual Studio中,可以追溯到2005年左右,这是一种相当方便的方法,我认为它仍然存在,尽管我有一段时间没有对此感到困惑。我发现MSDN或w3.org是很好的资源,尽管w3上的语言有时可能会被消化。

使用此xml:

<?xml version="1.0" encoding="utf-8"?>
<root>
    <a id="a1">
        <d id="1" />
        <d id="2" />
    </a>
    <a id="a2">
        <d id="3" />
        <d id="4" />
    </a>
    <b>
        <c id="1" />
        <c id="2" />
    </b>
</root>
Run Code Online (Sandbox Code Playgroud)

使用此xslt:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <test>
            <xsl:apply-templates/>
        </test>
    </xsl:template>

    <xsl:template match="b">
        <z>
            <select>//a</select>
            <xsl:copy-of select="//a"/>
        </z>
        <z>
            <select>.//a</select>
            <xsl:copy-of select=".//a"/>
        </z>
        <z>
            <select>.//c</select>
            <xsl:copy-of select=".//c"/>
        </z>
    <z>
        <select>/root/a/d</select>
        <xsl:copy-of select="/root/a/d"/>
    </z>
    <z>
            <select>/root/a</select>
            <xsl:copy-of select="/root/a"/>
        </z>
        <z>
            <question>so what is the node?</question>
            <period>
                <xsl:copy-of select="."/>
            </period>
            <slash>
                <xsl:copy-of select="/"/>
            </slash>
        </z>
    </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

得到这个结果:

<?xml version="1.0" encoding="utf-8"?>
<test>
  <z>
    <select>//a</select>
    <a id="a1">
      <d id="1" />
      <d id="2" />
    </a>
    <a id="a2">
      <d id="3" />
      <d id="4" />
    </a>
  </z>
  <z>
    <select>.//a</select>
  </z>
  <z>
    <select>.//c</select>
    <c id="1" />
    <c id="2" />
  </z>
  <z>
    <select>/root/a/d</select>
    <d id="1" />
    <d id="2" />
    <d id="3" />
    <d id="4" />
  </z>
  <z>
    <select>/root/a</select>
    <a id="a1">
      <d id="1" />
      <d id="2" />
    </a>
    <a id="a2">
      <d id="3" />
      <d id="4" />
    </a>
  </z>
  <z>
    <question>so what is the node?</question>
    <period>
      <b>
        <c id="1" />
        <c id="2" />
      </b>
    </period>
    <slash>
      <root>
        <a id="a1">
          <d id="1" />
          <d id="2" />
        </a>
        <a id="a2">
          <d id="3" />
          <d id="4" />
        </a>
        <b>
          <c id="1" />
          <c id="2" />
        </b>
      </root>
    </slash>
  </z>
</test>
Run Code Online (Sandbox Code Playgroud)

因此,在构建xpath时,//将获得该节点类型的后代,如果从xpath开始使用//,则将转到文档。

如果您从开始。那么您将以当前节点开始xpath(如果使用xsl:apply-templates,则当前节点与xsl:template中的匹配后的节点相同,但如果使用xsl:call-template,则当前节点是相同的作为制作xsl:call-template的当前节点)。

如果您以/开头的xpath,那么您将引用文档的根目录。

假定$ docId是一个节点集,该节点集引用一个文档或另一个文档,它设置了xpath的起点,因此$ docId // message意味着获取节点集中的所有消息元素,即$ docId。

最后,您需要//的原因是您没有完全指定路径。在提供的示例中,我构造了一个/ root / a / d,它是d元素的完整路径,并将所有4个元素拉出。$ docId // message仅允许您查找位于$ docId节点集根目录之下的任何元素“ message”。有时您可能没有清晰的对称性来获取记录:例如,如果您具有/ messages / critical / message和/ messages / warning / message,则使用/ messages // message的xpath可能更方便//获得所需信息的消息。

我希望这有帮助。