xmlstarlet XPath表达式选择单个结果而不是多个结果

时间:2015-10-12 11:27:39

标签: xml linux bash xpath xmlstarlet

我有一个XML文件,其结构如下:

<?xml version="1.0" encoding="UTF-8"?>
<hudson>
    <authorizationStrategy>
        <roleMap type="globalRoles">
            <role name="Employees">
                <assignedSIDs>
                    <sid>abc</sid>
                    <sid>bcd</sid>                      
                </assignedSIDs>
            </role>
        </roleMap>
        <roleMap type="projectRoles">   
            <role name="test1" pattern=".*">
                <assignedSIDs>
                    <sid>abc</sid>
                    <sid>zxc</sid>
                </assignedSIDs>
            </role>
            <role name="test2" pattern=".*">
                <permissions/>
                <assignedSIDs>
                    <sid>abc</sid>
                    <sid>ghi</sid>
                </assignedSIDs>
            </role>
            <role name="test3" pattern=".*">
                <permissions/>
                <assignedSIDs>
                    <sid>abc</sid>
                </assignedSIDs>
            </role>
        </roleMap>
    </authorizationStrategy>
</hudson>

以前,我没有给出有问题的整个结构和我得到解决方案的xpath,没有给出我预期的结果(在我的系统上,但它给了回答我的问题的人)在下面链接search tag attribute value based on child node value using XmlStarlet

如该链接中提到的,我想根据sid标签的值找到角色标签名称属性。例如:如果我搜索abc,查询必须返回Employees,test1,test2和test3。

这是我使用的脚本:

xmlstarlet sel -t -v "//role[.//sid = 'abc']/@name" test.xml

但它只给了我'员工'。

我正在使用LINUX / bash。请告诉我,XPATH表达式中缺少的是什么。

2 个答案:

答案 0 :(得分:1)

您使用的XPath和xmlstarlet命令,

xmlstarlet sel -t -v "//role[.//sid = 'abc']/@name" test.xml

已经导致返回以下字符串,

Employees
test1
test2
test3

按要求。

你的XPath是正确的;你的xmlstarlet命令行是正确的。重新检查您正在使用的文件名以及运行xmlstarlet的目录。重新检查您在实际上下文中如何使用xmlstarlet命令的结果。在您发布的这种简化形式中,预期结果正是返回的结果。

更新:很抱歉听到您仍然被卡住了。我的最后一个想法是发布一份详细的成绩单,以证明这应该有效,这样你就可以回溯你的步骤,并试着看看你的路径可能会有所不同:

c:\gd\usr\kjh\proj\try\xml
> cat test.xml
<?xml version="1.0" encoding="UTF-8"?>
<hudson>
    <authorizationStrategy>
        <roleMap type="globalRoles">
            <role name="Employees">
                <assignedSIDs>
                    <sid>abc</sid>
                    <sid>bcd</sid>
                </assignedSIDs>
            </role>
        </roleMap>
        <roleMap type="projectRoles">
            <role name="test1" pattern=".*">
                <assignedSIDs>
                    <sid>abc</sid>
                    <sid>zxc</sid>
                </assignedSIDs>
            </role>
            <role name="test2" pattern=".*">
                <permissions/>
                <assignedSIDs>
                    <sid>abc</sid>
                    <sid>ghi</sid>
                </assignedSIDs>
            </role>
            <role name="test3" pattern=".*">
                <permissions/>
                <assignedSIDs>
                    <sid>abc</sid>
                </assignedSIDs>
            </role>
        </roleMap>
    </authorizationStrategy>
</hudson>

c:\gd\usr\kjh\proj\try\xml
> xmlstarlet sel -t -v "//role[.//sid = 'abc']/@name" test.xml
Employees
test1
test2
test3
c:\gd\usr\kjh\proj\try\xml
> xmlstarlet --version
1.5.0
compiled against libxml2 2.9.1, linked with 20901
compiled against libxslt 1.1.28, linked with 10128

c:\gd\usr\kjh\proj\try\xml
> systeminfo | findstr /B /C:"OS Name" /C:"OS Version"
OS Name:                   Microsoft Windows 7 Professional
OS Version:                6.1.7601 Service Pack 1 Build 7601
c:\gd\usr\kjh\proj\try\xml
>

最终更新:

OP注意到他的xmlstarlet版本(v1.0.1)比我在上述脚本中使用的版本(xmlstarlet v1.5.0)要老得多。 升级到最新版本的xmlstarlet解决了这个问题。

答案 1 :(得分:0)

如果您不受xmlstarlet的约束,请尝试使用xmllint,否则调整xpath如下所示可能会有所帮助。

$ xmllint --xpath '//role//sid/../../@name' roles.xml
 name="Employees" name="Others"

此示例的xml文件类似于

<?xml version="1.0" ?>
<hudson>
  <authorizationStrategy>
    <roleMap>
      <role name="Employees">
        <assignedSIDs>
          <sid>abc</sid>
          <sid>bcd</sid>
        </assignedSIDs>
      </role>
      <role name="Others">
        <assignedSIDs>
          <sid>abc</sid>
          <sid>zxc</sid>
        </assignedSIDs>
      </role>
    </roleMap>
  </authorizationStrategy>
</hudson>

简而言之,您可以通过使用../@*来解决父级子属性。