id () в XPATH с .NET - PullRequest
       1

id () в XPATH с .NET

2 голосов
/ 11 сентября 2010

Я пытаюсь запросить XML через XPATH, но у меня проблема с получением id () для работы. Я хотел бы получить всех авторов для книги, указав ID книги.

Вот XML.

<?xml version="1.0" encoding="utf-8" ?>
<bookstore xmlns="http://litemedia.se/BookStore.xsd">
  <book id="ISBN9789170375033">
    <title>I väntan på talibanerna</title>
    <cover>http://image.bokus.com/images2/9789170375033_large</cover>
    <author-ref id="A1" />
  </book>

  <book id="ISBN9789170372063">
    <title>Sista resan till Phnom Penh</title>
    <cover>http://image.bokus.com/images2/9789170372063_large</cover>
    <author-ref id="A1" />
  </book>

  <book id="ISBN9789127121867">
    <title>Vårt bröllop : Kronprinsessan Victoria och Prins Daniel 19 juni 2010</title>
    <cover>http://image.bokus.com/images2/9789127121867_large</cover>
    <author-ref id="A2 A3" />    
  </book>

  <book id="ISBN9789189204966">
    <title>Människa, människa</title>
    <cover>http://image.bokus.com/images2/9789189204966_large</cover>
    <author-ref id="A3" />
  </book>

  <author id="A1">
    <name>Jesper Huor</name>
  </author>
  <author id="A2">
    <name>Susanna Popova</name>
  </author>
  <author id="A3">
    <name>Paul Hansen</name>
  </author>
</bookstore>

А это моя схема.

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="BookStore"
    targetNamespace="http://litemedia.se/BookStore.xsd"
    elementFormDefault="qualified"
    xmlns="http://litemedia.se/BookStore.xsd"
    xmlns:mstns="http://litemedia.se/BookStore.xsd"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
  <xs:element name="bookstore">
    <xs:complexType mixed="true">
      <xs:sequence>
        <xs:element name="book" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="title" type="xs:string" />
              <xs:element name="cover" type="xs:anyURI" />
              <xs:element name="author-ref">
                <xs:complexType>
                  <xs:attribute name="id" type="xs:IDREFS"/>
                </xs:complexType>
              </xs:element>
            </xs:sequence>

            <xs:attribute name="id" type="xs:ID" />
          </xs:complexType>
        </xs:element>

        <xs:element name="author" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="name" type="xs:string" />
            </xs:sequence>

            <xs:attribute name="id" type="xs:ID" />
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Это мой код.

public IList<Author> GetAuthorsForBook(string isbn)
{
    using (var xmlStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(XmlDataSourcePath))
    using (var xsdStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(XsdDataSourcePath))
    {
        var doc = new XmlDocument();

        // Load schema
        var schema = XmlSchema.Read(xsdStream, SchemaEvents);
        doc.Schemas.Add(schema);

        // Load document
        doc.Load(xmlStream);

        // Load default namespace: bs
        var nsmgr = new XmlNamespaceManager(doc.NameTable);
        nsmgr.AddNamespace("bs", "http://litemedia.se/BookStore.xsd");

        // We should be able to do this
        // var path = string.Format("id(id('{0}')/bs:author-ref/@id)", isbn);

        // but this will have to do
        var path = string.Format("/bs:bookstore/bs:author/@id[contains(/bs:bookstore/bs:book[@id='{0}']/bs:author-ref/@id,.)]", isbn);

        return doc.SelectNodes(path, nsmgr).Cast<XmlNode>()
            .Select(node =>
            new Author
            {
                Name = node.FirstChild.Value
            }).ToList();
    }
}

Поскольку я указал bookId и authorId в качестве типа идентификатора в схеме, я хотел бы иметь возможность сделать следующее.

var path = string.Format("id(id('{0}')/bs:author-ref/@id)", isbn);

Этот запрос всегда возвращает 0 элементов. Если я уменьшу его до идентификатора ('ISBN9789127121867'), который также вернет 0 результатов, что означает, что id () не работает в моем сценарии. (

В данный момент я собираюсь выполнить следующий запрос, даже если он не так эффективен, как использование id (), он даст мне нужные мне результаты.

var path = string.Format("/bs:bookstore/bs:author/@id[contains(/bs:bookstore/bs:book[@id='{0}']/bs:author-ref/@id,.)]", isbn);

У вас когда-нибудь была похожая проблема или какой-либо ключ к тому, что я мог сделать неправильно? Спасибо!

Микаэль Лундин

Ответы [ 3 ]

2 голосов
/ 12 сентября 2010

Как объяснено в моем комментарии, идентификаторы, определенные в схеме, не имеют значения для XPath 1.0.Чтобы дать вам пример того, как он работает с реализацией XPath 2.0 со схемой, вот некоторый код, использующий методы расширения XQSharp на узлах XmlNode:

    XmlDocument doc = new XmlDocument();
    XmlReaderSettings xrs = new XmlReaderSettings()
    {
        ValidationType = ValidationType.Schema
    };
    xrs.Schemas.Add(null, "schema.xsd");
    using (XmlReader xr = XmlReader.Create("input.xml", xrs))
    {
        doc.Load(xr);
    }

    string isbn = "ISBN9789127121867";

    XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
    nsmgr.AddNamespace("bs", "http://litemedia.se/BookStore.xsd");

    string path = string.Format("id(id('{0}')/bs:author-ref/@id)", isbn);
    foreach (XmlElement author in doc.XPathSelectNodes(path, nsmgr))
    {
        Console.WriteLine(author.OuterXml);
    }

Когда я запускаю это в проектегде я добавил ссылки на XQSharp и XQSharp.ExtensionMethods и добавил using XQSharp.ExtensionMethods;, он выводит два авторских элемента, например,

<author id="A2" xmlns="http://litemedia.se/BookStore.xsd"><name>Susanna Popova</name></author>
<author id="A3" xmlns="http://litemedia.se/BookStore.xsd"><name>Paul Hansen</name></author>
1 голос
/ 12 сентября 2010

AFAIK Функция XPath id() не реализована в XslCompiledTransform.

Например :

Таблица стилей XSLT :

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

 <xsl:template match="/">
  <xsl:copy-of select="id('a22')"/>
 </xsl:template>
</xsl:stylesheet>

Исходный XML-документ :

<!DOCTYPE test [
  <!ELEMENT test (x+)>
  <!ELEMENT x (x+| y+)>
  <!ATTLIST x
     a ID #REQUIRED>
  <!ELEMENT y ANY>
]>
<test>
    <x a="a11">
      <x a="a21">
        <x a="a31">
          <y>y31</y>
          <y>y32</y>
        </x>
      </x>
    </x>
    <x a="a12">
      <x a="a22">
        <y>y21</y>
        <y>y22</y>
      </x>
    </x>
    <x a="a13">
      <y>y11</y>
      <y>y12</y>
    </x>
    <x a="a14">
      <y>y03</y>
      <y>y04</y>
    </x>
</test>

Результаты с MSXML3 / 4 :

<x a="a22">
        <y>y21</y>
        <y>y22</y>
      </x>

Результат с XslCompiledTransform или с XslTransform :

(Nothing)
0 голосов
/ 12 сентября 2010

Iirc (из далекого прошлого) обработка идентификатора работает для xdr, но не для xsd.

Может быть, просто использовать // * [@ id = 'foo']

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...