【问题标题】:My XPATH expression is selecting an incorrect node set我的 XPATH 表达式选择了不正确的节点集
【发布时间】:2014-11-10 20:33:58
【问题描述】:

我正在尝试自学 XSL 和 XPATH。我有一个由我们的商业工具之一创建的示例 XML 文档,我想提取某些节点值并创建一个 CSV 文件作为输出。 XML 文档的截断示例如下:

<?xml version="1.0" encoding="windows-1252"?>
<xml_report> 
  <form id= "WOI:WorkOrder" xmlns="http://www.w3.org/2000/xforms">
     <mode l>
        < group name="field-info" minOccurs="1" maxOccurs="1">
            <group name="field" minOccurs="1" maxOccurs="*">
               <string name="name" />
               <number name="id" long="true" />
               <string name="type" range="closed">
                  <value>CHAR</value>
                  <value>TIME</value>
                  <value>DECIMAL</value>
                  <value>REAL</value>
                  <value>INT</value>
                  <value>ENUM</value>
                  <value>ATTACH</value>
                  <value>DIARY</value>
                  <value>TIMEOFDAY</value>
                 <value>DATE</value>
                 <value>CURRENCY</value>
                 <value>NULL</value>
              </string>
           </group>
           <!-- Additional group nodes -->
        </group>
     </model>
     <instance>
        <field-info>
           <field>
              <name>Work Order ID*&#43;</name>
              <id>1000000182</id>
              <type> CHAR</type>
           </field>
           <!-- Additional field nodes -->
        </field-info>
        <entry>
           <field_value>
              <value>WO0000000498983</value>
           </field_value>
           <field_value>
              <value>New Host name for new server build</value>
           </field_value>
        </entry>
        <!-- Additional entry nodes -->
     </instance>
  </form>
</xml_report>

我只想提取值元素的内容,过滤掉其他所有内容。我编写了一些非常简单的 XSL 来尝试这样做:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="text" omit-xml-declaration="yes" indent="yes" encoding="utf-8" media-type="text/plain" />
   <xsl:template match="/xml_report/form/instance">
      <xsl:for-each select="entry/field_value">
         <xsl:value-of select='value' /><xsl:text>,</xsl:text>
      </xsl:for-each>
   </xsl:template>
</xsl:stylesheet>

鉴于示例 XML,我希望得到以下输出:

WO0000000498983,New Host name for new server build,

问题是我实际上是在提取我实际想要使用的节点列表之前的所有元素的值,以及不需要的缩进和行间距。我认为在模板匹配和 for-each 标记中指定限制性 XPATH 表达式就足够了,但事实并非如此。如何将选定节点的范围缩小到只有我真正想要使用的那些?如果有帮助,我将使用 SAXON 作为 Windows 7 上的 XSLT 处理引擎。

              CHAR
              TIME
              DECIMAL
              REAL
              INT
              ENUM
              ATTACH
              DIARY
              TIMEOFDAY
              DATE
              CURRENCY
              NULL








           Work Order ID*+
           1000000182
            CHAR





           WO0000000498983


           New Host name for new server build

【问题讨论】:

    标签: xml xslt xpath


    【解决方案1】:

    由于表单元素的输入 XML 中的命名空间,您无法获得所需的输出:

    <form id="WOI:WorkOrder" xmlns="http://www.w3.org/2000/xforms">
    

    因此,此表单中的所有元素都具有在 XSLT 中不匹配的名称空间。 添加命名空间时,例如 xmlns:xforms="http://www.w3.org/2000/xforms",在 XSLT 之后

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0"
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       xmlns:xforms="http://www.w3.org/2000/xforms">
    <xsl:output method="text" omit-xml-declaration="yes" 
              indent="yes" encoding="utf-8" media-type="text/plain" />
    <xsl:template match="/xml_report">
    <xsl:copy>
        <xsl:apply-templates select="xforms:form"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="/xml_report">
        <xsl:apply-templates select="xforms:form/xforms:instance"/>   
    </xsl:template>
    <xsl:template match="xforms:instance">
      <xsl:for-each select="xforms:entry/xforms:field_value">
         <xsl:value-of select='xforms:value' /><xsl:text>,</xsl:text>
      </xsl:for-each>
    </xsl:template>
    </xsl:stylesheet>
    

    当应用于您的示例 XML 并在第 4 行中更正 &lt;model&gt; 而不是 &lt;mode l&gt; 时,会产生以下输出:

    WO0000000498983,New Host name for new server build,
    

    为了避免误解 - 在这个 XSLT 中,我刚刚将 xforms-namespace 添加为 xmlns:xforms,没有必要这样命名。它会例如可以将其声明为xmlns:xfo="http://www.w3.org/2000/xforms",然后将&lt;xsl:apply-templates select="xforms:form"/&gt; 更改为&lt;xsl:apply-templates select="xfo:form"/&gt;(并且还可以将其更改为当前以xforms: 为前缀的其他元素)。

    当您使用 XSLT 2.0 时,还可以将 xforms 命名空间声明为 xpath-default-namespace,因为您只针对此命名空间中的元素。调整后的 XSLT

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0" 
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
         xpath-default-namespace="http://www.w3.org/2000/xforms">
    <xsl:output method="text" omit-xml-declaration="yes" 
                indent="yes" encoding="utf-8" media-type="text/plain" />
    <xsl:template match="//form">
        <xsl:apply-templates select="instance"/>   
    </xsl:template>
    <xsl:template match="instance">
    <xsl:for-each select="entry/field_value">
         <xsl:value-of select='value' /><xsl:text>,</xsl:text>
      </xsl:for-each>
    </xsl:template>
    </xsl:stylesheet>
    

    产生相同的输出。因为xformsdefault namespace,所以不需要添加额外的命名空间和元素前缀。
    此版本的另一个调整是匹配form 而不是xml_report,因为xml_report 没有xforms 命名空间。

    作为命名空间的参考,您可以例如看看http://www.w3.org/TR/REC-xml-names/#ns-declWhat does "xmlns" in XML mean? 给出的有价值的答案

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-18
      • 1970-01-01
      • 2016-10-03
      • 1970-01-01
      • 2012-09-23
      • 2017-01-23
      相关资源
      最近更新 更多