Как получить содержимое элемента XML с помощью XmlSerializer? - PullRequest
3 голосов
/ 20 октября 2008

У меня есть читатель XML для этой строки XML:

<?xml version="1.0" encoding="UTF-8" ?>
<story id="1224488641nL21535800" date="20 Oct 2008" time="07:44">
<title>PRESS DIGEST - PORTUGAL - Oct 20</title>
<text>
<p>    LISBON, Oct 20 (Reuters) - Following are some of the main
 stories in Portuguese newspapers on Monday. Reuters has not
verified these stories and does not vouch for their accuracy. </p>
<p>More HTML stuff here</p>
</text>
</story>

Я создал XSD и соответствующий класс для десериализации.

[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
public class story {
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string id;
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string date;
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string time;
    public string title;
    public string text;
}

Затем я создаю экземпляр класса, используя метод Deserialize XmlSerializer.

XmlSerializer ser = new XmlSerializer(typeof(story));
return (story)ser.Deserialize(xr);

Теперь член text в story всегда равен нулю. Как изменить класс story, чтобы XML-код анализировался, как ожидалось?

РЕДАКТИРОВАТЬ:

Использование XmlText не работает, и я не могу контролировать XML, который я анализирую.

Ответы [ 9 ]

1 голос
/ 20 октября 2008

Вы можете реализовать IXmlSerializable для своего класса и обрабатывать там внутренние элементы, это означает, что вы сохраняете код для десериализации ваших данных внутри целевого класса (таким образом, избегая проблем с инкапсуляцией). Это достаточно простой тип данных, поэтому код должен быть тривиальным для записи.

1 голос
/ 20 октября 2008

Предложение, которое я собирался сделать, если текстовый тег содержал только p тегов, было следующим, это может быть полезно в краткосрочной перспективе.

Вместо истории, имеющей текстовое поле в виде строки, вы можете иметь его в виде массива строк. Затем вы можете использовать правильные атрибуты XmlArray (не могу вспомнить точные имена, что-то вроде XmlArrayItemAttribute) с правильными параметрами, чтобы он выглядел следующим образом:

<text>
   <p>blah</p>
   <p>blib</p>
</text>

Что на шаг ближе, но не совсем то, что вам нужно.

Другой вариант - создать класс вроде:

public class Text //Obviously a bad name for a class...
{
   public string[] p;
   public string[] pre;
}

И снова используйте атрибуты XmlArray, чтобы он выглядел правильно, не уверен, что они так же настраиваемы, как раньше, потому что раньше я использовал их только для простых типов.

Edit:

Использование:

[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
    public class story
    {
        [System.Xml.Serialization.XmlAttributeAttribute()]
        public string id;
        [System.Xml.Serialization.XmlAttributeAttribute()]
        public string date;
        [System.Xml.Serialization.XmlAttributeAttribute()]
        public string time;
        public string title;

        [XmlArrayItem("p")]
        public string[] text;

    }

Хорошо работает с предоставленным XML, но иметь класс кажется немного сложнее. В итоге получается что-то похожее на:

<code>    <text>
       <p>
          <p>qwertyuiop</p>
          <p>asdfghjkl</p>
       </p>
       <pre>
          <pre>stuff
nonsense

что явно не то, что нужно.

1 голос
/ 20 октября 2008

Я нашел очень неудовлетворительное решение.

Измените класс следующим образом (тьфу!)

// ...
[XmlElement("HACK - this should never match anything")]
public string text;
// ...

И измените код вызова следующим образом (чёрт!)

XmlSerializer ser = new XmlSerializer(typeof(story));
string text = string.Empty;
ser.UnknownElement += delegate(object sender, XmlElementEventArgs e) {
    if (e.Element.Name != "text")
        throw new XmlException(
              string.Format(CultureInfo.InvariantCulture, 
             "Unknown element '{0}' cannot be deserialized.",
             e.Element.Name));
    text += e.Element.InnerXml;
};

story result = (story)ser.Deserialize(xr);
result.text = text;
return result;

Это действительно плохой способ сделать это, потому что он нарушает инкапсуляцию . Есть ли лучший способ сделать это?

0 голосов
/ 22 августа 2012

Я столкнулся с той же проблемой после использования XSD.exe для генерации XSD из XML, а затем XSD для классов. Я добавил тег [XmlText] перед классом объекта в сгенерированном файле класса (в моем случае он назывался P из-за тега <p>, который он выводил как узел XML), и он работал мгновенно. вытащить весь HTML-контент, находящийся внутри родительского узла, и вставить этот объект P, который я затем переименовал в нечто более полезное.

0 голосов
/ 07 ноября 2008

Пожалуйста, взгляните на похожий вопрос, который я задал ... это может помочь ответить на ваш вопрос

0 голосов
/ 07 ноября 2008

Вы пробовали xsd.exe ? Он позволяет вам создавать xsd из документов xml и затем генерировать классы из xsd, которые должны быть готовы для десериализации xml.

0 голосов
/ 20 октября 2008

Возможно, использование атрибута XmlAnyElement вместо обработки события UnknownElement может быть более элегантным.

0 голосов
/ 20 октября 2008

Поскольку у вас нет контроля над XML, вы можете вместо этого использовать StreamReader. XmlReader интерпретирует теги HTML как XML, а это не то, что вам нужно.

Однако XmlSerializer удалит теги HTML внутри текстового тега.

0 голосов
/ 20 октября 2008

Мне кажется, что XML неверен. Поскольку вы используете теги HTML внутри текстового тега, теги HTML интерпретируются как XML. Вы должны использовать CDATA для правильной интерпретации данных или экранирования <и>.

...