【问题标题】:XPath translate to lower case not workingXPath 转换为小写不工作
【发布时间】:2012-12-10 13:11:32
【问题描述】:

xml 文件看起来像

<employees>    
 <employee id='1'>
  <Profile_Name>admin</Profile_Name>
  <UserName>user</UserName>
 </employee>

 <employee id='2'>
  <Profile_Name>Admin</Profile_Name>
  <UserName>USER</UserName>
 </employee>

 <employee id='3'>
  <Profile_Name>Adminnn</Profile_Name>
  <UserName>userrrr</UserName>
 </employee>

这是我的 xpath

         employees/employee
                     [not(Deleted)]
                       [Profile_Name[last()]
                          [translate(., 
                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
                                     'abcdefghijklmnopqrstuvwxyz'
                                     )
                          ]
                          =
                           'admin'or 
                           UserName[last()]
                                    [translate(.,
                                               'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
                                                'abcdefghijklmnopqrstuvwxyz'
                                              )
                                    ]
                               =
                                'user'
                         ]

它应该选择没有Deleted 子元素和Profile_Name = admin 或UserName = user 的employee 元素,无论profileName 和UserName 的情况如何

它工作正常,但不考虑字符大小写。

它应该返回employeeid = 1 和 2

【问题讨论】:

  • 编辑问题并提供: 1) 完整(但简短)的 XML 文档; 2)必须选择哪些节点。 3) 选择规则说明。
  • @DimitreNovaatchev:完成
  • HebaEl-Fadly,我编辑了问题并格式化了 XPath 表达式,使其现在可读且易于理解。请参阅我的答案以获取我认为选择所需节点的 XPath 表达式。
  • 查看更新的答案——我添加了基于 XSLT 的验证,这表明选择了正确的元素。

标签: .net xml xpath


【解决方案1】:

现在你有这个(正确格式化以使其可读):

           /employees/employee
                     [not(Deleted)]
                       [Profile_Name[last()]
                          [translate(Profile_Name[last()], 
                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
                                     'abcdefghijklmnopqrstuvwxyz'
                                     )
                          ]
                          =
                           'admin'or 
                           UserName[last()]
                                    [translate(.,
                                               'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
                                                'abcdefghijklmnopqrstuvwxyz'
                                              )
                                    ]
                               =
                                'user'
                         ]";

显然是错误的——包含translate()的谓词关闭得太早了。

可能你想要这个

        /employees/employee
                     [not(Deleted)]
                           [translate(Profile_Name[last()], 
                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
                                     'abcdefghijklmnopqrstuvwxyz'
                                     )
                          =
                           'admin'
                         or 
                           translate(UserName[last()],
                                      'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
                                      'abcdefghijklmnopqrstuvwxyz'
                                      )
                           =
                            'user'
                            ]

基于 XSLT 的验证

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
     <xsl:copy-of select=
     "/employees/employee
                     [not(Deleted)]
                           [translate(Profile_Name[last()],
                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
                                     'abcdefghijklmnopqrstuvwxyz'
                                     )
                          =
                           'admin'
                         or
                           translate(UserName[last()],
                                      'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
                                      'abcdefghijklmnopqrstuvwxyz'
                                      )
                           =
                            'user'
                      ]"/>
 </xsl:template>
</xsl:stylesheet>

此转换应用于以下 XML 文档时(基于提供的文档,但添加了更多 employee 元素以提供更多必要的测试案例):

<employees>
    <employee id='1'>
        <Profile_Name>admin</Profile_Name>
        <UserName>user</UserName>
    </employee>
    <employee id='2'>
        <Profile_Name>Admin</Profile_Name>
        <UserName>USER</UserName>
    </employee>
    <employee id='3'>
      <Deleted/>
        <Profile_Name>Admin</Profile_Name>
        <UserName>user</UserName>
    </employee>
    <employee id='4'>
        <Profile_Name>Adminnn</Profile_Name>
        <UserName>userrrr</UserName>
    </employee>
</employees>

计算 Xpath 表达式并将计算结果复制到输出:

<employee id="1">
   <Profile_Name>admin</Profile_Name>
   <UserName>user</UserName>
</employee>
<employee id="2">
   <Profile_Name>Admin</Profile_Name>
   <UserName>USER</UserName>
</employee>

【讨论】:

    【解决方案2】:

    你的翻译放错地方了。您的代码生成的 XPath 表达式将测试类似

    Profile_Name[last()][translate(.,'ABCDE...', 'abcde...')] = 'foo'
    

    即它将找到最后一个Profile_Name 元素,检查该元素是否具有非空值,然后将该值(例如Foo)与字符串foo 进行比较。相反,您需要

    translate(Profile_Name[last()],'ABCDE...', 'abcde...') = 'foo'
    

    对翻译值而不是原始值进行比较。完整的表达式应该是这样的

     var xpath = "/employees/employee[not(Deleted)][translate(Profile_Name[last()],'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')='" + ProfileName.ToLower() + "' or translate(UserName[last()],'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')='" + UserName.ToLower() + "']";
    

    【讨论】:

    • 我已将其更新为var xpath = "/employees/employee[not(Deleted)][translate([Profile_Name[last()],'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')='" + ProfileName.ToLower() + "']" + " or [translate(UserName[last()],'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')='" + UserName.ToLower() + "']]";,但仍然无法使用
    • @HebaEl-Fadly 你还有太多的方括号。我已经完全编辑了我认为应该是正确的表达方式。
    【解决方案3】:

    .NET XSLT 实现允许在样式表中编写自定义托管函数。对于小写(),它可以是:

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:utils="urn:myExtension" exclude-result-prefixes="msxsl">
    
      <xsl:output method="xml" indent="yes"/>
    
      <msxsl:script implements-prefix="utils" language="C#">
        <![CDATA[
          public string ToLower(string stringValue)
          {
            string result = String.Empty;
    
            if(!String.IsNullOrEmpty(stringValue))
            {
              result = stringValue.ToLower(); 
            }
    
            return result;
          }
        ]]>
      </msxsl:script>
    
      <!-- using of our custom function -->
      <lowercaseValue>
        <xsl:value-of select="utils:ToLower($myParam)"/>
      </lowercaseValue>
    

    假设,这可能会很慢,但仍然可以接受。

    不要忘记为转换启用嵌入式脚本支持:

    // Create the XsltSettings object with script enabled.
    XsltSettings xsltSettings = new XsltSettings(false, true);
    
    XslCompiledTransform xslt = new XslCompiledTransform();
    
    // Load stylesheet
    xslt.Load(xsltPath, xsltSettings, new XmlUrlResolver());
    

    【讨论】:

      猜你喜欢
      • 2018-02-07
      • 2012-03-21
      • 1970-01-01
      • 1970-01-01
      • 2014-03-30
      • 2011-07-21
      • 2015-10-12
      • 2022-01-24
      • 2018-11-21
      相关资源
      最近更新 更多